/******************************************************************************* * Copyright (c) 2012, 2013 Ericsson * Copyright (c) 2010, 2011 École Polytechnique de Montréal * Copyright (c) 2010, 2011 Alexandre Montplaisir * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.eclipse.linuxtools.internal.tmf.core.statesystem; import java.io.IOException; import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend; import org.eclipse.linuxtools.tmf.core.component.TmfComponent; import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest; import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest; import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest; import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager; import org.eclipse.linuxtools.tmf.core.signal.TmfTraceClosedSignal; import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal; import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateProvider; import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystemBuilder; import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange; import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment; /** * This is the high-level wrapper around the State History and its provider and * storage plugins. Just create the object using the constructor then .run() * * You can use one HistoryBuilder and it will instantiate everything underneath. * If you need more fine-grained control you can still ignore this and * instantiate everything manually. * * @author alexmont * */ public class HistoryBuilder extends TmfComponent { private final ITmfStateProvider sp; private final StateSystem ss; private final IStateHistoryBackend hb; private boolean started = true; /* Don't handle signals until we're ready */ /** * Instantiate a new HistoryBuilder helper. The provider -> ss -> backend * relationships should have been set up already. * * @param stateProvider * The state provider plugin to use * @param ss * The state system object that will receive the state changes * from the provider * @param backend * The back-end storage to use, which will receive the intervals * from the ss * @param buildManually * Should we build this history in-band or not. True means we * will start the building ourselves and block the caller until * construction is done. False (out-of-band) means we will start * listening for the signal and return immediately. */ public HistoryBuilder(ITmfStateProvider stateProvider, StateSystem ss, IStateHistoryBackend backend, boolean buildManually) { if (stateProvider == null || backend == null || ss == null) { throw new IllegalArgumentException(); } if (stateProvider.getAssignedStateSystem() != ss) { /* Logic check to make sure the provider is setup properly */ throw new IllegalArgumentException(); } sp = stateProvider; hb = backend; this.ss = ss; if (buildManually) { TmfSignalManager.deregister(this); this.buildManually(); } else { started = false; /* We'll now wait for the signal to start building */ } } /** * Factory-style method to open an existing history, you only have to * provide the already-instantiated IStateHistoryBackend object. * * @param hb * The history-backend object * @return A IStateSystemBuilder reference to the new state system. If you * will only run queries on this history, you should *definitely* * cast it to IStateSystemQuerier. * @throws IOException * If there was something wrong. */ public static ITmfStateSystemBuilder openExistingHistory( IStateHistoryBackend hb) throws IOException { return new StateSystem(hb, false); } /** * Return a read/write reference to the state system object that was * created. * * @return Reference to the state system, with access to everything. */ public ITmfStateSystemBuilder getStateSystemBuilder() { return ss; } /** * Return a read-only reference to the state system object that was created. * * @return Reference to the state system, but only with the query methods * available. */ public ITmfStateSystem getStateSystemQuerier() { return ss; } /** * Build the state history without waiting for signals or anything */ private void buildManually() { StateSystemBuildRequest request = new StateSystemBuildRequest(this); /* Send the request to the trace here, since there is probably no * experiment. */ sp.getTrace().sendRequest(request); try { request.waitForCompletion(); } catch (InterruptedException e) { e.printStackTrace(); } } // ------------------------------------------------------------------------ // Signal handlers // ------------------------------------------------------------------------ /** * Listen to the "trace range updated" signal to start the state history * construction. * * @param signal * The "trace range updated" signal. Listening to this * signal will coalesce this request with the one from the * indexer and histogram. */ @TmfSignalHandler public void traceRangeUpdated(final TmfTraceRangeUpdatedSignal signal) { ITmfTrace sender = signal.getTrace(); if (!signalIsForUs(sender)) { return; } if (!started) { started = true; StateSystemBuildRequest request = new StateSystemBuildRequest(this); sender.sendRequest(request); } } /** * Listen to the "trace closed" signal to clean up if necessary. * * @param signal * The "trace closed" signal. */ @TmfSignalHandler public void traceClosed(TmfTraceClosedSignal signal) { ITmfTrace sender = signal.getTrace(); if (signalIsForUs(sender) && !started) { close(true); } } /** * Check if this signal is for this trace, or for an experiment containing * this trace. */ private boolean signalIsForUs(ITmfTrace sender) { if (sender instanceof TmfExperiment) { /* Yeah doing a lazy instanceof check here, but it's a special case! */ TmfExperiment exp = (TmfExperiment) sender; for (ITmfTrace childTrace : exp.getTraces()) { if (childTrace == sp.getTrace()) { return true; } } } else if (sender == sp.getTrace()) { return true; } return false; } // ------------------------------------------------------------------------ // Methods reserved for the request object below // ------------------------------------------------------------------------ /** Get the state provider object */ ITmfStateProvider getStateProvider() { return sp; } void close(boolean deleteFiles) { sp.dispose(); if (deleteFiles) { hb.removeFiles(); } dispose(); } } class StateSystemBuildRequest extends TmfEventRequest { /** The amount of events queried at a time through the requests */ private static final int CHUNK_SIZE = 50000; private final HistoryBuilder builder; private final ITmfStateProvider sci; private final ITmfTrace trace; StateSystemBuildRequest(HistoryBuilder builder) { super(builder.getStateProvider().getExpectedEventType(), TmfTimeRange.ETERNITY, TmfDataRequest.ALL_DATA, CHUNK_SIZE, ITmfDataRequest.ExecutionType.BACKGROUND); this.builder = builder; this.sci = builder.getStateProvider(); this.trace = sci.getTrace(); } @Override public void handleData(final ITmfEvent event) { super.handleData(event); if (event != null && event.getTrace() == trace) { sci.processEvent(event); } } @Override public void handleSuccess() { super.handleSuccess(); builder.close(false); } @Override public void handleCancel() { super.handleCancel(); builder.close(true); } @Override public void handleFailure() { super.handleFailure(); builder.close(true); } }