blob: c02156dc92dffa19964bf726192108e56eef6adc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Ericsson, École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Francois Chouinard - Initial API and implementation
* Francois Chouinard - Updated as per TMF Trace Model 1.0
* Patrick Tasse - Updated for removal of context clone
* Patrick Tasse - Updated for ranks in experiment location
* Geneviève Bastien - Added support of experiment synchronization
* Added the initExperiment method and default constructor
* Bernd Hufmann - Updated for added interfaces to ITmfEventProvider
*******************************************************************************/
package org.eclipse.tracecompass.tmf.core.trace.experiment;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.io.File;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.internal.tmf.core.synchronization.TmfTimestampTransform;
import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentContext;
import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentContext.ContextTuple;
import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfExperimentLocation;
import org.eclipse.tracecompass.internal.tmf.core.trace.experiment.TmfLocationArray;
import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
import org.eclipse.tracecompass.tmf.core.event.aspect.TmfBaseAspects;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
import org.eclipse.tracecompass.tmf.core.project.model.ITmfPropertiesProvider;
import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSynchronizedSignal;
import org.eclipse.tracecompass.tmf.core.synchronization.ITmfTimestampTransform;
import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationAlgorithm;
import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationManager;
import org.eclipse.tracecompass.tmf.core.synchronization.TimestampTransformFactory;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
/**
* TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
* that are part of a tracing experiment.
*
* @version 1.0
* @author Francois Chouinard
*/
public class TmfExperiment extends TmfTrace implements ITmfPersistentlyIndexable {
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
/**
* The file name of the Synchronization
*/
private static final String SYNCHRONIZATION_FILE_NAME = "synchronization.bin"; //$NON-NLS-1$
/**
* The name of the directory containing trace synchronization data. This
* directory typically will be preserved when traces are synchronized.
* Analysis involved in synchronization can put their supplementary files in
* there so they are not deleted when synchronized traces are copied.
*/
private static final String SYNCHRONIZATION_DIRECTORY = "sync_data"; //$NON-NLS-1$
/**
* The default index page size
*/
public static final int DEFAULT_INDEX_PAGE_SIZE = 5000;
/**
* Property name for traces defining a clock offset.
*/
private static final String CLOCK_OFFSET_PROPERTY = "clock_offset"; //$NON-NLS-1$
/**
* If the automatic clock offset is higher than this value, emit a warning.
*/
private static final long CLOCK_OFFSET_THRESHOLD_NS = 500000;
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
/**
* The set of traces that constitute the experiment
*/
private boolean fInitialized = false;
/**
* Lock for synchronization methods. These methods cannot be 'synchronized'
* since it makes it impossible to use an event request on the experiment
* during synchronization (the request thread would block)
*/
private final Lock fSyncLock = new ReentrantLock();
// ------------------------------------------------------------------------
// Construction
// ------------------------------------------------------------------------
/**
* Default constructor. Should not be used directly, but is needed for
* extension points.
*
* @deprecated Do not call this directly (but do not remove it either!)
*/
@Deprecated
public TmfExperiment() {
super();
}
/**
* Constructor of an experiment, taking the type, path, traces,
* indexPageSize and resource
*
* @param type
* The event type
* @param path
* The experiment path
* @param traces
* The experiment set of traces
* @param indexPageSize
* The experiment index page size. You can use
* {@link TmfExperiment#DEFAULT_INDEX_PAGE_SIZE} for a default
* value.
* @param resource
* The resource associated to the experiment. You can use 'null'
* for no resources (tests, etc.)
*/
public TmfExperiment(final Class<? extends ITmfEvent> type,
final String path,
final ITmfTrace[] traces,
final int indexPageSize,
final @Nullable IResource resource) {
initExperiment(type, path, traces, indexPageSize, resource, TmfTraceType.DEFAULT_EXPERIMENT_TYPE);
}
@Override
protected ITmfTraceIndexer createIndexer(int interval) {
if (getCheckpointSize() > 0) {
return new TmfBTreeTraceIndexer(this, interval);
}
return super.createIndexer(interval);
}
/**
* Clears the experiment
*/
@Override
public synchronized void dispose() {
// Clean up the index if applicable
if (getIndexer() != null) {
getIndexer().dispose();
}
super.dispose();
}
// ------------------------------------------------------------------------
// ITmfTrace - Initializers
// ------------------------------------------------------------------------
@Override
public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> type) {
/* Do nothing for experiments */
}
/**
* Initialization of an experiment, taking the type, path, traces,
* indexPageSize, resource and trace type id
*
* @param type
* the event type
* @param path
* the experiment path
* @param traces
* the experiment set of traces
* @param indexPageSize
* the experiment index page size
* @param resource
* the resource associated to the experiment
* @param traceTypeId
* the trace type id
* @since 5.0
*/
public void initExperiment(final Class<? extends ITmfEvent> type,
final String path,
final ITmfTrace[] traces,
final int indexPageSize,
final @Nullable IResource resource,
final String traceTypeId) {
try {
super.initTrace(resource, path, type, getName(), traceTypeId);
} catch (TmfTraceException e) {
Activator.logError("Error initializing experiment", e); //$NON-NLS-1$
}
initExperiment(type, path, traces, indexPageSize, resource);
}
/**
* Initialization of an experiment, taking the type, path, traces,
* indexPageSize and resource
*
* @param type
* the event type
* @param path
* the experiment path
* @param traces
* the experiment set of traces
* @param indexPageSize
* the experiment index page size
* @param resource
* the resource associated to the experiment
*/
public void initExperiment(final Class<? extends ITmfEvent> type,
final String path,
final ITmfTrace[] traces,
final int indexPageSize,
final @Nullable IResource resource) {
setCacheSize(indexPageSize);
setStreamingInterval(0);
Multimap<String, ITmfTrace> tracesPerHost = HashMultimap.create();
// traces have to be set before super.initialize()
if (traces != null) {
// initialize
for (ITmfTrace trace : traces) {
if (trace != null) {
tracesPerHost.put(trace.getHostId(), trace);
addChild(trace);
}
}
}
try {
super.initialize(resource, path, type);
} catch (TmfTraceException e) {
Activator.logError("Error initializing experiment", e); //$NON-NLS-1$
}
if (resource != null) {
synchronizeTraces();
}
/*
* For all traces on the same host, if two or more specify different
* clock offsets, adjust their clock offset by the average of all of them.
*
* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=484620
*/
Function<ITmfPropertiesProvider, @Nullable Long> offsetGetter = trace -> {
String offset = trace.getProperties().get(CLOCK_OFFSET_PROPERTY);
if (offset == null) {
return null;
}
try {
return Long.parseLong(offset);
} catch (NumberFormatException e) {
return null;
}
};
for (Collection<ITmfTrace> values : tracesPerHost.asMap().values()) {
/*
* Only attempt to synchronize traces that provide a clock_offset
* property.
*/
Collection<ITmfPropertiesProvider> tracesToSynchronize = values.stream()
.filter(ITmfPropertiesProvider.class::isInstance)
.map(ITmfPropertiesProvider.class::cast)
.filter(trace -> offsetGetter.apply(trace) != null)
.collect(Collectors.toList());
if (tracesToSynchronize.size() < 2) {
continue;
}
/* Only synchronize traces if they haven't previously been synchronized */
if (tracesToSynchronize.stream()
.map(trace -> ((ITmfTrace) trace).getTimestampTransform())
.anyMatch(transform -> !transform.equals(TmfTimestampTransform.IDENTITY))) {
continue;
}
/* Calculate the average of all clock offsets */
BigInteger sum = BigInteger.ZERO;
for (ITmfPropertiesProvider trace : tracesToSynchronize) {
long offset = checkNotNull(offsetGetter.apply(trace));
sum = sum.add(BigInteger.valueOf(offset));
}
long average = sum.divide(BigInteger.valueOf(tracesToSynchronize.size())).longValue();
if (average > CLOCK_OFFSET_THRESHOLD_NS) {
Activator.logWarning("Average clock correction (" + average + ") is higher than threshold of " + //$NON-NLS-1$ //$NON-NLS-2$
CLOCK_OFFSET_THRESHOLD_NS + " ns for experiment " + this.toString()); //$NON-NLS-1$
}
/*
* Apply the offset correction to all identified traces, but only if
* they do not already have an equivalent one (for example, closing
* and re-opening the same experiment should not retrigger building
* all supplementary files).
*/
tracesToSynchronize.forEach(t -> {
long offset = checkNotNull(offsetGetter.apply(t));
long delta = average - offset;
ITmfTrace trace = (ITmfTrace) t;
ITmfTimestampTransform currentTransform = trace.getTimestampTransform();
ITmfTimestampTransform newTransform = TimestampTransformFactory.createWithOffset(delta);
if (!newTransform.equals(currentTransform)) {
TmfTraceManager.deleteSupplementaryFiles(trace);
trace.setTimestampTransform(newTransform);
}
});
}
}
@Override
public IStatus validate(final IProject project, final String path) {
return Status.OK_STATUS;
}
// ------------------------------------------------------------------------
// Accessors
// ------------------------------------------------------------------------
/**
* Get the traces contained in this experiment.
*
* @return The array of contained traces
*/
public List<@NonNull ITmfTrace> getTraces() {
return getChildren(ITmfTrace.class);
}
/**
* Returns the timestamp of the event at the requested index. If none,
* returns null.
*
* @param index
* the event index (rank)
* @return the corresponding event timestamp
*/
public ITmfTimestamp getTimestamp(final int index) {
final ITmfContext context = seekEvent(index);
final ITmfEvent event = getNext(context);
context.dispose();
return (event != null) ? event.getTimestamp() : null;
}
// ------------------------------------------------------------------------
// Request management
// ------------------------------------------------------------------------
@Override
public synchronized ITmfContext armRequest(final ITmfEventRequest request) {
// Make sure we have something to read from
if (getChildren().isEmpty()) {
return null;
}
if (!TmfTimestamp.BIG_BANG.equals(request.getRange().getStartTime())
&& request.getIndex() == 0) {
final ITmfContext context = seekEvent(request.getRange().getStartTime());
request.setStartIndex((int) context.getRank());
return context;
}
return seekEvent(request.getIndex());
}
// ------------------------------------------------------------------------
// ITmfTrace trace positioning
// ------------------------------------------------------------------------
@Override
public synchronized ITmfContext seekEvent(final ITmfLocation location) {
// Validate the location
if (location != null && !(location instanceof TmfExperimentLocation)) {
return null; // Throw an exception?
}
int length = getNbChildren();
// Initialize the location array if necessary
TmfLocationArray locationArray = ((location == null) ? new TmfLocationArray(length) : ((TmfExperimentLocation) location).getLocationInfo());
ITmfLocation[] locations = locationArray.getLocations();
long[] ranks = locationArray.getRanks();
// Create and populate the context's traces contexts
final TmfExperimentContext context = new TmfExperimentContext(length);
// Position the traces
long rank = 0;
for (int i = 0; i < length; i++) {
// Get the relevant trace attributes
final ITmfContext traceContext = ((ITmfTrace) getChild(i)).seekEvent(locations[i]);
traceContext.setRank(ranks[i]);
// update location after seek
locations[i] = traceContext.getLocation();
context.setContent(i, traceContext, ((ITmfTrace) getChild(i)).getNext(traceContext));
rank += ranks[i];
}
// Finalize context
context.setLocation(new TmfExperimentLocation(new TmfLocationArray(locations, ranks)));
context.setRank(rank);
return context;
}
// ------------------------------------------------------------------------
// ITmfTrace - SeekEvent operations (returning a trace context)
// ------------------------------------------------------------------------
@Override
public ITmfContext seekEvent(final double ratio) {
final ITmfContext context = seekEvent(Math.round(ratio * getNbEvents()));
return context;
}
@Override
public double getLocationRatio(final ITmfLocation location) {
if (location instanceof TmfExperimentLocation) {
long rank = 0;
TmfLocationArray locationArray = ((TmfExperimentLocation) location).getLocationInfo();
for (int i = 0; i < locationArray.size(); i++) {
rank += locationArray.getRank(i);
}
return (double) rank / getNbEvents();
}
return 0.0;
}
@Override
public ITmfLocation getCurrentLocation() {
// never used
return null;
}
@Override
public @NonNull Iterable<ITmfEventAspect<?>> getEventAspects() {
List<ITmfTrace> traces = getTraces();
ImmutableSet.Builder<ITmfEventAspect<?>> builder = new ImmutableSet.Builder<>();
/* For experiments, we'll add a "trace name" aspect/column */
builder.add(TmfBaseAspects.getTraceNameAspect());
String commonTraceType = getCommonTraceType();
if (commonTraceType != null) {
/*
* All the traces in this experiment are of the same type, let's
* just use the normal table for that type.
*/
builder.addAll(traces.get(0).getEventAspects());
} else {
/*
* There are different trace types in the experiment, so we are
* definitely using a TmfEventsTable. Aggregate the columns from all
* trace types.
*/
for (ITmfTrace trace : traces) {
Iterable<ITmfEventAspect<?>> traceAspects = trace.getEventAspects();
builder.addAll(traceAspects);
}
}
return builder.build();
}
/**
* Check if an experiment contains traces of all the same type. If so,
* returns this type as a String. If not, returns null.
*
* @param experiment
* The experiment
* @return The common trace type if there is one, or 'null' if there are
* different types.
*/
private @Nullable String getCommonTraceType() {
String commonTraceType = null;
try {
for (final ITmfTrace trace : getTraces()) {
final IResource resource = trace.getResource();
if (resource == null) {
return null;
}
final String traceType = resource.getPersistentProperty(TmfCommonConstants.TRACETYPE);
if ((commonTraceType != null) && !commonTraceType.equals(traceType)) {
return null;
}
commonTraceType = traceType;
}
} catch (CoreException e) {
/*
* One of the traces didn't advertise its type, we can't infer
* anything.
*/
return null;
}
return commonTraceType;
}
// ------------------------------------------------------------------------
// ITmfTrace trace positioning
// ------------------------------------------------------------------------
@Override
public synchronized ITmfEvent parseEvent(final ITmfContext context) {
final ITmfContext tmpContext = seekEvent(context.getLocation());
final ITmfEvent event = getNext(tmpContext);
return event;
}
@Override
public synchronized ITmfEvent getNext(ITmfContext context) {
// Make sure that we have something to read from
if (getNbChildren() == 0) {
return null;
}
// Validate the context
if (!(context instanceof TmfExperimentContext)) {
return null; // Throw an exception?
}
TmfExperimentContext experimentContext = (TmfExperimentContext) context;
// Identify the "next" trace to read from
ContextTuple next = experimentContext.getNext();
ITmfEvent event = null;
if (next != null) {
event = next.getEvent();
updateAttributes(experimentContext, event);
experimentContext.increaseRank();
// Update the experiment location
ITmfLocation location = experimentContext.getLocation();
if (location instanceof TmfExperimentLocation) {
int trace = next.getIndex();
ITmfContext traceContext = next.getContext();
TmfLocationArray locationArray = new TmfLocationArray(
((TmfExperimentLocation) location).getLocationInfo(),
trace, traceContext.getLocation(), traceContext.getRank());
experimentContext.setLocation(new TmfExperimentLocation(locationArray));
// queue the next event
ITmfEvent nextEvent = ((ITmfTrace) getChild(trace)).getNext(traceContext);
experimentContext.setContent(trace, traceContext, nextEvent);
}
}
return event;
}
@Override
public ITmfTimestamp getInitialRangeOffset() {
List<ITmfTrace> children = getChildren(ITmfTrace.class);
if (children.isEmpty()) {
return super.getInitialRangeOffset();
}
ITmfTimestamp initTs = TmfTimestamp.BIG_CRUNCH;
for (ITmfTrace trace : children) {
ITmfTimestamp ts = (trace).getInitialRangeOffset();
if (ts.compareTo(initTs) < 0) {
initTs = ts;
}
}
return initTs;
}
/**
* Get the path to the folder in the supplementary file where
* synchronization-related data can be kept so they are not deleted when the
* experiment is synchronized. Analysis involved in synchronization can put
* their supplementary files in there so they are preserved after
* synchronization.
*
* If the directory does not exist, it will be created. A return value of
* <code>null</code> means either the trace resource does not exist or
* supplementary resources cannot be kept.
*
* @param absolute
* If <code>true</code>, it returns the absolute path in the file
* system, including the supplementary file path. Otherwise, it
* returns only the directory name.
* @return The path to the folder where synchronization-related
* supplementary files can be kept or <code>null</code> if not
* available.
*/
public String getSynchronizationFolder(boolean absolute) {
/* Set up the path to the synchronization file we'll use */
IResource resource = this.getResource();
String syncDirectory = null;
try {
/* get the directory where the file will be stored. */
if (resource != null) {
String fullDirectory = resource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER);
/* Create the synchronization data directory if not present */
if (fullDirectory != null) {
fullDirectory = fullDirectory + File.separator + SYNCHRONIZATION_DIRECTORY;
File syncDir = new File(fullDirectory);
syncDir.mkdirs();
}
if (absolute) {
syncDirectory = fullDirectory;
} else {
syncDirectory = SYNCHRONIZATION_DIRECTORY;
}
}
} catch (CoreException e) {
return null;
}
return syncDirectory;
}
/**
* Synchronizes the traces of an experiment. By default it only tries to
* read a synchronization file if it exists
*
* @return The synchronization object
*/
public SynchronizationAlgorithm synchronizeTraces() {
return synchronizeTraces(false);
}
/**
* Synchronizes the traces of an experiment.
*
* @param doSync
* Whether to actually synchronize or just try opening a sync
* file
* @return The synchronization object
*/
public SynchronizationAlgorithm synchronizeTraces(boolean doSync) {
fSyncLock.lock();
try {
String syncDirectory = getSynchronizationFolder(true);
final File syncFile = (syncDirectory != null) ? new File(syncDirectory + File.separator + SYNCHRONIZATION_FILE_NAME) : null;
final SynchronizationAlgorithm syncAlgo = SynchronizationManager.synchronizeTraces(syncFile, Collections.singleton(this), doSync);
final TmfTraceSynchronizedSignal signal = new TmfTraceSynchronizedSignal(this, syncAlgo);
/* Broadcast in separate thread to prevent deadlock */
new Thread() {
@Override
public void run() {
broadcast(signal);
}
}.start();
return syncAlgo;
} finally {
fSyncLock.unlock();
}
}
@Override
@SuppressWarnings("nls")
public synchronized String toString() {
return "[TmfExperiment (" + getName() + ")]";
}
// ------------------------------------------------------------------------
// Streaming support
// ------------------------------------------------------------------------
private synchronized void initializeStreamingMonitor() {
if (fInitialized) {
return;
}
fInitialized = true;
if (getStreamingInterval() == 0) {
final ITmfContext context = seekEvent(0);
final ITmfEvent event = getNext(context);
context.dispose();
if (event == null) {
return;
}
final TmfTimeRange timeRange = new TmfTimeRange(event.getTimestamp(), TmfTimestamp.BIG_CRUNCH);
final TmfTraceRangeUpdatedSignal signal = new TmfTraceRangeUpdatedSignal(this, this, timeRange);
// Broadcast in separate thread to prevent deadlock
new Thread() {
@Override
public void run() {
broadcast(signal);
}
}.start();
return;
}
final Thread thread = new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
private ITmfTimestamp safeTimestamp = null;
private ITmfTimestamp lastSafeTimestamp = null;
private TmfTimeRange timeRange = null;
@Override
public void run() {
while (!executorIsShutdown()) {
if (!getIndexer().isIndexing()) {
ITmfTimestamp startTimestamp = TmfTimestamp.BIG_CRUNCH;
ITmfTimestamp endTimestamp = TmfTimestamp.BIG_BANG;
for (final ITmfTrace trace : getChildren(ITmfTrace.class)) {
if (trace.getStartTime().compareTo(startTimestamp) < 0) {
startTimestamp = trace.getStartTime();
}
if (trace.getStreamingInterval() != 0 && trace.getEndTime().compareTo(endTimestamp) > 0) {
endTimestamp = trace.getEndTime();
}
}
ITmfTimestamp safeTs = safeTimestamp;
if (safeTs != null && (lastSafeTimestamp == null || safeTs.compareTo(lastSafeTimestamp) > 0)) {
timeRange = new TmfTimeRange(startTimestamp, safeTs);
lastSafeTimestamp = safeTs;
} else {
timeRange = null;
}
safeTimestamp = endTimestamp;
if (timeRange != null) {
final TmfTraceRangeUpdatedSignal signal = new TmfTraceRangeUpdatedSignal(TmfExperiment.this, TmfExperiment.this, timeRange);
broadcast(signal);
}
}
try {
Thread.sleep(getStreamingInterval());
} catch (final InterruptedException e) {
// Do nothing
}
}
}
};
thread.start();
}
@Override
public long getStreamingInterval() {
long interval = 0;
for (final ITmfTrace trace : getChildren(ITmfTrace.class)) {
interval = Math.max(interval, trace.getStreamingInterval());
}
return interval;
}
// ------------------------------------------------------------------------
// Signal handlers
// ------------------------------------------------------------------------
@Override
@TmfSignalHandler
public void traceOpened(TmfTraceOpenedSignal signal) {
if (signal.getTrace() == this) {
initializeStreamingMonitor();
/* Initialize the analysis */
MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null);
status.add(executeAnalysis());
if (!status.isOK()) {
Activator.log(status);
}
/* Refresh supplementary files in separate thread to prevent deadlock */
new Thread("Refresh supplementary files") { //$NON-NLS-1$
@Override
public void run() {
TmfTraceManager.refreshSupplementaryFiles(TmfExperiment.this);
}
}.start();
}
}
@Override
public synchronized int getCheckpointSize() {
int totalCheckpointSize = 0;
try {
List<ITmfTrace> children = getChildren(ITmfTrace.class);
for (ITmfTrace trace : children) {
if (!(trace instanceof ITmfPersistentlyIndexable)) {
return 0;
}
ITmfPersistentlyIndexable persistableIndexTrace = (ITmfPersistentlyIndexable) trace;
int currentTraceCheckpointSize = persistableIndexTrace.getCheckpointSize();
if (currentTraceCheckpointSize <= 0) {
return 0;
}
totalCheckpointSize += currentTraceCheckpointSize;
// each entry in the TmfLocationArray has a rank in addition
// of the location
totalCheckpointSize += 8;
}
} catch (UnsupportedOperationException e) {
return 0;
}
return totalCheckpointSize;
}
@Override
public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
List<ITmfTrace> children = getChildren(ITmfTrace.class);
int length = children.size();
ITmfLocation[] locations = new ITmfLocation[length];
long[] ranks = new long[length];
for (int i = 0; i < length; ++i) {
final ITmfTrace trace = children.get(i);
locations[i] = ((ITmfPersistentlyIndexable) trace).restoreLocation(bufferIn);
ranks[i] = bufferIn.getLong();
}
TmfLocationArray arr = new TmfLocationArray(locations, ranks);
TmfExperimentLocation l = new TmfExperimentLocation(arr);
return l;
}
}