X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=org.eclipse.linuxtools.tmf.core%2Fsrc%2Forg%2Feclipse%2Flinuxtools%2Ftmf%2Fcore%2Ftrace%2FTmfTrace.java;h=ecee99cd7ce6001dd8d4cff183144485db80845c;hb=5419a136f6d2c00435f7fc07b19a0246bc7bb5fb;hp=3883e6b0fc7bf4abdd81d405676e37e69071447c;hpb=20f27c02913b3cbb73aa3ac0998e3313ae6ec234;p=deliverable%2Ftracecompass.git diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java index 3883e6b0fc..ecee99cd7c 100644 --- a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java +++ b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java @@ -1,11 +1,11 @@ /******************************************************************************* - * Copyright (c) 2009, 2010 Ericsson - * + * Copyright (c) 2009, 2010, 2012 Ericsson + * * 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 - * + * * Contributors: * Francois Chouinard - Initial API and implementation * Francois Chouinard - Updated as per TMF Trace Model 1.0 @@ -14,76 +14,106 @@ package org.eclipse.linuxtools.tmf.core.trace; import java.io.File; -import java.io.FileNotFoundException; -import java.util.Collections; -import java.util.Vector; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; -import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider; import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp; import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange; import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp; +import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest; import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest; -import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest; -import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest; -import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; +import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal; +import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; +import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics; +import org.eclipse.linuxtools.tmf.core.statistics.TmfStateStatistics; /** - * TmfTrace + * Abstract implementation of ITmfTrace. *

- * Abstract implementation of ITmfTrace. It should be sufficient to extend this - * class and provide implementation for getCurrentLocation() and - * seekLocation(), as well as a proper parser, to have a working - * concrete implementation. + * Since the concept of 'location' is trace specific, the concrete classes have + * to provide the related methods, namely: + *

+ * A concrete trace must provide its corresponding parser. A common way to + * accomplish this is by making the concrete class extend TmfTrace and + * implement ITmfEventParser. + *

+ * The concrete class can either specify its own indexer or use the provided + * TmfCheckpointIndexer (default). In this case, the trace cache size will be + * used as checkpoint interval. + * + * @version 1.0 + * @author Francois Chouinard + * + * @see ITmfEvent + * @see ITmfTraceIndexer + * @see ITmfEventParser */ -public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace { - - // ------------------------------------------------------------------------ - // Constants - // ------------------------------------------------------------------------ - - /** - * The default number of events in an index page. Can be used as block size. - */ - public static final int DEFAULT_INDEX_PAGE_SIZE = 1000; +public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace { // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ + // The resource used for persistent properties for this trace + private IResource fResource; + // The trace path private String fPath; - /** - * The cache page size AND checkpoints interval - */ - protected int fIndexPageSize = DEFAULT_INDEX_PAGE_SIZE; + // The trace cache page size + private int fCacheSize = ITmfTrace.DEFAULT_TRACE_CACHE_SIZE; - // The set of event stream checkpoints - protected Vector fCheckpoints = new Vector(); - - // The number of events collected - protected long fNbEvents = 0; + // The number of events collected (so far) + private long fNbEvents = 0; // The time span of the event stream - private ITmfTimestamp fStartTime = TmfTimestamp.BIG_CRUNCH; + private ITmfTimestamp fStartTime = TmfTimestamp.BIG_BANG; private ITmfTimestamp fEndTime = TmfTimestamp.BIG_BANG; + // The trace streaming interval (0 = no streaming) + private long fStreamingInterval = 0; + + // The trace indexer + private ITmfTraceIndexer fIndexer; + + // The trace parser + private ITmfEventParser fParser; + + // The trace's statistics + private ITmfStatistics fStatistics; + + // The current selected time + private ITmfTimestamp fCurrentTime = TmfTimestamp.ZERO; + + // The current selected range + private TmfTimeRange fCurrentRange = TmfTimeRange.NULL_RANGE; + /** - * The trace streaming interval (0 = no streaming) + * The collection of state systems that are registered with this trace. Each + * sub-class can decide to add its (one or many) state system to this map + * during their {@link #buildStateSystem()}. + * + * @since 2.0 */ - protected long fStreamingInterval = 0; - - // The resource used for persistent properties for this trace - private IResource fResource; + protected final Map fStateSystems = + new HashMap(); // ------------------------------------------------------------------------ // Construction @@ -97,451 +127,520 @@ public abstract class TmfTrace extends TmfEventProvider } /** - * The standard constructor (non-streaming trace) - * - * @param name the trace display name + * The standard constructor (non-live trace). Applicable when the trace + * implements its own parser and if at checkpoint-based index is OK. + * + * @param resource the resource associated to the trace * @param type the trace event type * @param path the trace path - * @param pageSize the trace index page size - * @param indexTrace whether to start indexing the trace or not - * @throws FileNotFoundException + * @param cacheSize the trace cache size + * @throws TmfTraceException If something failed during the opening */ - protected TmfTrace(final String name, final Class type, final String path, final int indexPageSize, final boolean indexTrace) throws FileNotFoundException { - this(name, type, path, 0, indexPageSize, indexTrace); + protected TmfTrace(final IResource resource, final Class type, final String path, final int cacheSize) throws TmfTraceException { + this(resource, type, path, cacheSize, 0); } /** - * The full constructor - * - * @param name the trace display name + * The standard constructor (live trace). Applicable when the trace + * implements its own parser and if at checkpoint-based index is OK. + * + * @param resource the resource associated to the trace * @param type the trace event type * @param path the trace path - * @param pageSize the trace index page size - * @param indexTrace whether to start indexing the trace or not - * @throws FileNotFoundException + * @param cacheSize the trace cache size + * @param interval the trace streaming interval + * @throws TmfTraceException If something failed during the opening */ - protected TmfTrace(final String name, final Class type, final String path, final long interval, final int indexPageSize, final boolean indexTrace) throws FileNotFoundException { + protected TmfTrace(final IResource resource, final Class type, final String path, final int cacheSize, final long interval) throws TmfTraceException { + this(resource, type, path, cacheSize, interval, null); + } + + /** + * The 'non-default indexer' constructor. Allows to provide a trace + * specific indexer. + * + * @param resource the resource associated to the trace + * @param type the trace event type + * @param path the trace path + * @param cacheSize the trace cache size + * @param interval the trace streaming interval + * @param indexer the trace indexer + * @throws TmfTraceException If something failed during the opening + */ + protected TmfTrace(final IResource resource, final Class type, final String path, final int cacheSize, + final long interval, final ITmfTraceIndexer indexer) throws TmfTraceException { + this(resource, type, path, cacheSize, interval, indexer, null); + } + + /** + * The full constructor where trace specific indexer/parser are provided. + * + * @param resource the resource associated to the trace + * @param type the trace event type + * @param path the trace path + * @param cacheSize the trace cache size + * @param interval the trace streaming interval + * @param indexer the trace indexer + * @param parser the trace event parser + * @throws TmfTraceException If something failed during the opening + */ + protected TmfTrace(final IResource resource, final Class type, final String path, final int cacheSize, + final long interval, final ITmfTraceIndexer indexer, final ITmfEventParser parser) throws TmfTraceException { super(); - initTrace(name, path, type); + fCacheSize = (cacheSize > 0) ? cacheSize : ITmfTrace.DEFAULT_TRACE_CACHE_SIZE; fStreamingInterval = interval; - fIndexPageSize = (indexPageSize >0) ? indexPageSize : DEFAULT_INDEX_PAGE_SIZE; - if (indexTrace) - indexTrace(false); + fIndexer = (indexer != null) ? indexer : new TmfCheckpointIndexer(this, fCacheSize); + fParser = parser; + initialize(resource, path, type); } /** * Copy constructor - * + * * @param trace the original trace + * @throws TmfTraceException Should not happen usually */ - @SuppressWarnings("unchecked") - public TmfTrace(final ITmfTrace trace) throws FileNotFoundException { + public TmfTrace(final TmfTrace trace) throws TmfTraceException { super(); - if (trace == null) + if (trace == null) { throw new IllegalArgumentException(); - initTrace(getName(), getPath(), (Class) getType()); - fStreamingInterval = getStreamingInterval(); - fIndexPageSize = getIndexPageSize(); - indexTrace(false); + } + fCacheSize = trace.getCacheSize(); + fStreamingInterval = trace.getStreamingInterval(); + fIndexer = new TmfCheckpointIndexer(this); + fParser = trace.fParser; + initialize(trace.getResource(), trace.getPath(), trace.getEventType()); } // ------------------------------------------------------------------------ - // Cloneable + // ITmfTrace - Initializers // ------------------------------------------------------------------------ /* (non-Javadoc) - * @see java.lang.Object#clone() + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class) */ @Override - @SuppressWarnings("unchecked") - public TmfTrace clone() { - TmfTrace clone = null; - try { - clone = (TmfTrace) super.clone(); - // clone.fTrace = fTrace; - // clone.fRank = fRank; - // clone.fTimestamp = fTimestamp != null ? fTimestamp.clone() : null; - // clone.fSource = fSource; - // clone.fType = fType != null ? fType.clone() : null; - // clone.fContent = fContent != null ? fContent.clone() : null; - // clone.fReference = fReference; - } catch (final CloneNotSupportedException e) { - } - return clone; + public void initTrace(final IResource resource, final String path, final Class type) throws TmfTraceException { + fIndexer = new TmfCheckpointIndexer(this, fCacheSize); + initialize(resource, path, type); } - // ------------------------------------------------------------------------ - // ITmfTrace - initializers - // ------------------------------------------------------------------------ - - /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#initTrace(java.lang.String, java.lang.String, java.lang.Class) + /** + * Initialize the trace common attributes and the base component. + * + * @param resource the Eclipse resource (trace) + * @param path the trace path + * @param type the trace event type + * + * @throws TmfTraceException If something failed during the initialization */ - @Override - public void initTrace(final String name, final String path, final Class type) throws FileNotFoundException { + protected void initialize(final IResource resource, final String path, final Class type) throws TmfTraceException { + if (path == null) { + throw new TmfTraceException("Invalid trace path"); //$NON-NLS-1$ + } fPath = path; - String traceName = name; - // If no display name was provided, extract it from the trace path - if (traceName == null) - if (path != null) { - final int sep = path.lastIndexOf(Path.SEPARATOR); - traceName = (sep >= 0) ? path.substring(sep + 1) : path; - } else - traceName = ""; //$NON-NLS-1$ + fResource = resource; + String traceName = (resource != null) ? resource.getName() : null; + // If no resource was provided, extract the display name the trace path + if (traceName == null) { + final int sep = path.lastIndexOf(IPath.SEPARATOR); + traceName = (sep >= 0) ? path.substring(sep + 1) : path; + } + if (fParser == null) { + if (this instanceof ITmfEventParser) { + fParser = (ITmfEventParser) this; + } else { + throw new TmfTraceException("Invalid trace parser"); //$NON-NLS-1$ + } + } super.init(traceName, type); } - /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String) + /** + * Indicates if the path points to an existing file/directory + * + * @param path the path to test + * @return true if the file/directory exists */ - @Override - public boolean validate(final IProject project, final String path) { + protected boolean fileExists(final String path) { final File file = new File(path); return file.exists(); } - /* - * (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#setResource(org.eclipse.core.resources.IResource) + /** + * Index the trace + * + * @param waitForCompletion index synchronously (true) or not (false) */ - @Override - public void setResource(final IResource resource) { - fResource = resource; + protected void indexTrace(boolean waitForCompletion) { + getIndexer().buildIndex(0, TmfTimeRange.ETERNITY, waitForCompletion); } - // ------------------------------------------------------------------------ - // ITmfTrace - accessors - // ------------------------------------------------------------------------ + /** + * The default implementation of TmfTrace uses a TmfStatistics back-end. + * Override this if you want to specify another type (or none at all). + * + * @throws TmfTraceException + * If there was a problem setting up the statistics + * @since 2.0 + */ + protected void buildStatistics() throws TmfTraceException { + /* + * Initialize the statistics provider, but only if a Resource has been + * set (so we don't build it for experiments, for unit tests, etc.) + */ + fStatistics = (fResource == null ? null : new TmfStateStatistics(this) ); + } /** - * @return the trace path + * Build the state system(s) associated with this trace type. + * + * Suppressing the warning, because the 'throws' will usually happen in + * sub-classes. + * + * @throws TmfTraceException + * If there is a problem during the build + * @since 2.0 */ - @Override - public String getPath() { - return fPath; + @SuppressWarnings("unused") + protected void buildStateSystem() throws TmfTraceException { + /* + * Nothing is done in the base implementation, please specify + * how/if to register a new state system in derived classes. + */ + return; } - /* - * (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource() + /** + * Clears the trace */ @Override - public IResource getResource() { - return fResource; + public synchronized void dispose() { + /* Clean up the index if applicable */ + if (getIndexer() != null) { + getIndexer().dispose(); + } + + /* Clean up the statistics */ + if (fStatistics != null) { + fStatistics.dispose(); + } + + /* Clean up the state systems */ + for (ITmfStateSystem ss : fStateSystems.values()) { + ss.dispose(); + } + + super.dispose(); } + // ------------------------------------------------------------------------ + // ITmfTrace - Basic getters + // ------------------------------------------------------------------------ + /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents() + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getEventType() */ @Override - public synchronized long getNbEvents() { - return fNbEvents; + public Class getEventType() { + return (Class) super.getType(); } /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange() + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource() */ @Override - public TmfTimeRange getTimeRange() { - return new TmfTimeRange(fStartTime, fEndTime); + public IResource getResource() { + return fResource; } /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime() + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getPath() */ @Override - public ITmfTimestamp getStartTime() { - return fStartTime.clone(); + public String getPath() { + return fPath; } /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime() + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize() */ @Override - public ITmfTimestamp getEndTime() { - return fEndTime.clone(); + public int getCacheSize() { + return fCacheSize; } /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval() + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getStreamingInterval() */ @Override public long getStreamingInterval() { return fStreamingInterval; } - /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize() + /** + * @return the trace indexer */ - @Override - public int getIndexPageSize() { - return fIndexPageSize; + protected ITmfTraceIndexer getIndexer() { + return fIndexer; } - // ------------------------------------------------------------------------ - // ITmfTrace - indexing - // ------------------------------------------------------------------------ - - /* - * The index is a list of contexts that point to events at regular interval - * (rank-wise) in the trace. After it is built, the index can be used to - * quickly access any event by rank or timestamp. - * - * fIndexPageSize holds the event interval (default INDEX_PAGE_SIZE). + /** + * @return the trace parser */ + protected ITmfEventParser getParser() { + return fParser; + } + /** + * @since 2.0 + */ @Override - @SuppressWarnings({ "unchecked" }) - public void indexTrace(final boolean waitForCompletion) { - - // The monitoring job - final Job job = new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$ - @Override - protected IStatus run(final IProgressMonitor monitor) { - while (!monitor.isCanceled()) - try { - Thread.sleep(100); - } catch (final InterruptedException e) { - return Status.OK_STATUS; - } - monitor.done(); - return Status.OK_STATUS; - } - }; - job.schedule(); - - // Clear the checkpoints - fCheckpoints.clear(); - - // Build a background request for all the trace data. The index is - // updated as we go by getNextEvent(). - final ITmfEventRequest request = new TmfEventRequest(ITmfEvent.class, TmfTimeRange.ETERNITY, - TmfDataRequest.ALL_DATA, fIndexPageSize, ITmfDataRequest.ExecutionType.BACKGROUND) - { - ITmfTimestamp startTime = null; - ITmfTimestamp lastTime = null; - - @Override - public void handleData(final ITmfEvent event) { - super.handleData(event); - if (event != null) { - final ITmfTimestamp timestamp = event.getTimestamp(); - if (startTime == null) - startTime = timestamp.clone(); - lastTime = timestamp.clone(); - - // Update the trace status at regular intervals - if ((getNbRead() % fIndexPageSize) == 0) - updateTraceStatus(); - } - } - - @Override - public void handleSuccess() { - updateTraceStatus(); - } - - @Override - public void handleCompleted() { - job.cancel(); - super.handleCompleted(); - } - - private synchronized void updateTraceStatus() { - final int nbRead = getNbRead(); - if (nbRead != 0) { - fStartTime = startTime; - fEndTime = lastTime; - fNbEvents = nbRead; - notifyListeners(); - } - } - }; + public ITmfStatistics getStatistics() { + return fStatistics; + } - // Submit the request and wait for completion if required - sendRequest((ITmfDataRequest) request); - if (waitForCompletion) - try { - request.waitForCompletion(); - } catch (final InterruptedException e) { - } + /** + * @since 2.0 + */ + @Override + public final ITmfStateSystem getStateSystem(String id) { + return fStateSystems.get(id); } - private void notifyListeners() { - broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime))); + /** + * @since 2.0 + */ + @Override + public final Collection listStateSystems() { + return fStateSystems.keySet(); } // ------------------------------------------------------------------------ - // ITmfTrace - seek operations + // ITmfTrace - Trace characteristics getters // ------------------------------------------------------------------------ /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getNbEvents() */ @Override - public ITmfContext seekEvent(final ITmfTimestamp ts) { - - ITmfTimestamp timestamp = ts; - if (timestamp == null) - timestamp = TmfTimestamp.BIG_BANG; - - // First, find the right checkpoint - int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null)); - - // In the very likely case that the checkpoint was not found, bsearch - // returns its negated would-be location (not an offset...). From that - // index, we can then position the stream and get the event. - if (index < 0) - index = Math.max(0, -(index + 2)); - - // Position the stream at the checkpoint - ITmfLocation location; - synchronized (fCheckpoints) { - if (!fCheckpoints.isEmpty()) { - if (index >= fCheckpoints.size()) - index = fCheckpoints.size() - 1; - location = fCheckpoints.elementAt(index).getLocation(); - } else - location = null; - } - final ITmfContext context = seekLocation(location); - context.setRank(index * fIndexPageSize); - - // And locate the event - final ITmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype... - ITmfEvent event = getNextEvent(nextEventContext); - while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) { - context.setLocation(nextEventContext.getLocation().clone()); - context.increaseRank(); - event = getNextEvent(nextEventContext); - } + public synchronized long getNbEvents() { + return fNbEvents; + } - return context; + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getTimeRange() + */ + @Override + public TmfTimeRange getTimeRange() { + return new TmfTimeRange(fStartTime, fEndTime); } /* (non-Javadoc) - * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getStartTime() */ @Override - public ITmfContext seekEvent(final long rank) { - - // Position the stream at the previous checkpoint - int index = (int) rank / fIndexPageSize; - ITmfLocation location; - synchronized (fCheckpoints) { - if (fCheckpoints.isEmpty()) - location = null; - else { - if (index >= fCheckpoints.size()) - index = fCheckpoints.size() - 1; - location = fCheckpoints.elementAt(index).getLocation(); - } - } + public ITmfTimestamp getStartTime() { + return fStartTime; + } - final ITmfContext context = seekLocation(location); - long pos = index * fIndexPageSize; - context.setRank(pos); + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getEndTime() + */ + @Override + public ITmfTimestamp getEndTime() { + return fEndTime; + } - if (pos < rank) { - ITmfEvent event = getNextEvent(context); - while (event != null && ++pos < rank) - event = getNextEvent(context); - } + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentTime() + */ + /** + * @since 2.0 + */ + @Override + public ITmfTimestamp getCurrentTime() { + return fCurrentTime; + } - return context; + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentRange() + */ + /** + * @since 2.0 + */ + @Override + public TmfTimeRange getCurrentRange() { + return fCurrentRange; } - // ------------------------------------------------------------------------ - // Operations - // ------------------------------------------------------------------------ + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getInitialRangeOffset() + */ + /** + * @since 2.0 + */ + @Override + public ITmfTimestamp getInitialRangeOffset() { + final long DEFAULT_INITIAL_OFFSET_VALUE = (1L * 100 * 1000 * 1000); // .1sec + return new TmfTimestamp(DEFAULT_INITIAL_OFFSET_VALUE, ITmfTimestamp.NANOSECOND_SCALE); + } // ------------------------------------------------------------------------ - // Operations + // Convenience setters // ------------------------------------------------------------------------ - @SuppressWarnings("unchecked") - public Vector getCheckpoints() { - return (Vector) fCheckpoints.clone(); + /** + * Set the trace cache size. Must be done at initialization time. + * + * @param cacheSize The trace cache size + */ + protected void setCacheSize(final int cacheSize) { + fCacheSize = cacheSize; } /** - * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event - * (if any). - * - * @param timestamp the requested event timestamp - * @return the corresponding event rank + * Set the trace known number of events. This can be quite dynamic + * during indexing or for live traces. + * + * @param nbEvents The number of events */ - @Override - public long getRank(final ITmfTimestamp timestamp) { - final ITmfContext context = seekEvent(timestamp); - return context.getRank(); + protected synchronized void setNbEvents(final long nbEvents) { + fNbEvents = (nbEvents > 0) ? nbEvents : 0; } - // ------------------------------------------------------------------------ - // Operators - // ------------------------------------------------------------------------ - + /** + * Update the trace events time range + * + * @param range the new time range + */ protected void setTimeRange(final TmfTimeRange range) { fStartTime = range.getStartTime(); fEndTime = range.getEndTime(); } + /** + * Update the trace chronologically first event timestamp + * + * @param startTime the new first event timestamp + */ protected void setStartTime(final ITmfTimestamp startTime) { fStartTime = startTime; } + /** + * Update the trace chronologically last event timestamp + * + * @param endTime the new last event timestamp + */ protected void setEndTime(final ITmfTimestamp endTime) { fEndTime = endTime; } + /** + * Set the polling interval for live traces (default = 0 = no streaming). + * + * @param interval the new trace streaming interval + */ + protected void setStreamingInterval(final long interval) { + fStreamingInterval = (interval > 0) ? interval : 0; + } + + /** + * Set the trace indexer. Must be done at initialization time. + * + * @param indexer the trace indexer + */ + protected void setIndexer(final ITmfTraceIndexer indexer) { + fIndexer = indexer; + } + + /** + * Set the trace parser. Must be done at initialization time. + * + * @param parser the new trace parser + */ + protected void setParser(final ITmfEventParser parser) { + fParser = parser; + } + // ------------------------------------------------------------------------ - // TmfProvider + // ITmfTrace - SeekEvent operations (returning a trace context) // ------------------------------------------------------------------------ + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long) + */ @Override - public ITmfContext armRequest(final ITmfDataRequest request) { - if (request instanceof ITmfEventRequest - && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest) request).getRange().getStartTime()) && request.getIndex() == 0) { - final ITmfContext context = seekEvent(((ITmfEventRequest) request).getRange().getStartTime()); - ((ITmfEventRequest) request).setStartIndex((int) context.getRank()); + public synchronized ITmfContext seekEvent(final long rank) { + + // A rank <= 0 indicates to seek the first event + if (rank <= 0) { + ITmfContext context = seekEvent((ITmfLocation) null); + context.setRank(0); return context; + } + // Position the trace at the checkpoint + final ITmfContext context = fIndexer.seekIndex(rank); + + // And locate the requested event context + long pos = context.getRank(); + if (pos < rank) { + ITmfEvent event = getNext(context); + while ((event != null) && (++pos < rank)) { + event = getNext(context); + } } - return seekEvent(request.getIndex()); + return context; } - /** - * Return the next piece of data based on the context supplied. The context would typically be updated for the - * subsequent read. - * - * @param context - * @return the event referred to by context + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp) */ - @SuppressWarnings("unchecked") @Override - public T getNext(final ITmfContext context) { - if (context instanceof TmfContext) - return (T) getNextEvent(context); - return null; + public synchronized ITmfContext seekEvent(final ITmfTimestamp timestamp) { + + // A null timestamp indicates to seek the first event + if (timestamp == null) { + ITmfContext context = seekEvent((ITmfLocation) null); + context.setRank(0); + return context; + } + + // Position the trace at the checkpoint + ITmfContext context = fIndexer.seekIndex(timestamp); + + // And locate the requested event context + final ITmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype... + ITmfEvent event = getNext(nextEventContext); + while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) { + context.dispose(); + context = nextEventContext.clone(); + event = getNext(nextEventContext); + } + nextEventContext.dispose(); + if (event == null) { + context.setLocation(null); + context.setRank(ITmfContext.UNKNOWN_RANK); + } + return context; } // ------------------------------------------------------------------------ - // ITmfTrace + // ITmfTrace - Read operations (returning an actual event) // ------------------------------------------------------------------------ - - /* - * (non-Javadoc) - * - * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse. - * linuxtools.tmf.trace.ITmfTrace.TraceContext) + /* (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#readNextEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext) */ @Override - public synchronized ITmfEvent getNextEvent(final ITmfContext context) { + public synchronized ITmfEvent getNext(final ITmfContext context) { // parseEvent() does not update the context - final ITmfEvent event = parseEvent(context); + final ITmfEvent event = fParser.parseEvent(context); if (event != null) { - updateIndex(context, context.getRank(), event.getTimestamp()); + updateAttributes(context, event.getTimestamp()); context.setLocation(getCurrentLocation()); context.increaseRank(); processEvent(event); @@ -549,36 +648,176 @@ public abstract class TmfTrace extends TmfEventProvider return event; } - protected synchronized void updateIndex(final ITmfContext context, final long rank, final ITmfTimestamp timestamp) { - if (fStartTime.compareTo(timestamp, false) > 0) + /** + * Hook for special event processing by the concrete class + * (called by TmfTrace.getEvent()) + * + * @param event the event + */ + protected void processEvent(final ITmfEvent event) { + // Do nothing + } + + /** + * Update the trace attributes + * + * @param context the current trace context + * @param timestamp the corresponding timestamp + */ + protected synchronized void updateAttributes(final ITmfContext context, final ITmfTimestamp timestamp) { + if (fStartTime.equals(TmfTimestamp.BIG_BANG) || (fStartTime.compareTo(timestamp, false) > 0)) { fStartTime = timestamp; - if (fEndTime.compareTo(timestamp, false) < 0) + } + if (fEndTime.equals(TmfTimestamp.BIG_CRUNCH) || (fEndTime.compareTo(timestamp, false) < 0)) { fEndTime = timestamp; + } + if (fCurrentRange == TmfTimeRange.NULL_RANGE) { + fCurrentTime = timestamp; + ITmfTimestamp initialOffset = getInitialRangeOffset(); + long endValue = timestamp.getValue() + initialOffset.normalize(0, timestamp.getScale()).getValue(); + ITmfTimestamp endTimestamp = new TmfTimestamp(endValue, timestamp.getScale()); + fCurrentRange = new TmfTimeRange(timestamp, endTimestamp); + } if (context.hasValidRank()) { - if (fNbEvents <= rank) + long rank = context.getRank(); + if (fNbEvents <= rank) { fNbEvents = rank + 1; - // Build the index as we go along - if ((rank % fIndexPageSize) == 0) { - // Determine the table position - final long position = rank / fIndexPageSize; - // Add new entry at proper location (if empty) - if (fCheckpoints.size() == position) { - final ITmfLocation location = context.getLocation().clone(); - fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location)); - // System.out.println(getName() + "[" + (fCheckpoints.size() - // - 1) + "] " + timestamp + ", " + location.toString()); + } + if (fIndexer != null) { + fIndexer.updateIndex(context, timestamp); + } + } + } + + // ------------------------------------------------------------------------ + // TmfDataProvider + // ------------------------------------------------------------------------ + + /** + * @since 2.0 + */ + @Override + public synchronized ITmfContext armRequest(final ITmfDataRequest request) { + if (executorIsShutdown()) { + return null; + } + if ((request instanceof ITmfEventRequest) + && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest) request).getRange().getStartTime()) + && (request.getIndex() == 0)) + { + final ITmfContext context = seekEvent(((ITmfEventRequest) request).getRange().getStartTime()); + ((ITmfEventRequest) request).setStartIndex((int) context.getRank()); + return context; + + } + return seekEvent(request.getIndex()); + } + + // ------------------------------------------------------------------------ + // Signal handlers + // ------------------------------------------------------------------------ + + /** + * Handler for the Trace Opened signal + * + * @param signal + * The incoming signal + * @since 2.0 + */ + @TmfSignalHandler + public void traceOpened(TmfTraceOpenedSignal signal) { + ITmfTrace trace = signal.getTrace(); + if (signal.getTrace() instanceof TmfExperiment) { + TmfExperiment experiment = (TmfExperiment) signal.getTrace(); + for (ITmfTrace expTrace : experiment.getTraces()) { + if (expTrace == this) { + trace = expTrace; + break; + } + } + } + if (trace == this) { + /* the signal is for this trace or for an experiment containing this trace */ + try { + buildStatistics(); + } catch (TmfTraceException e) { + e.printStackTrace(); + } + try { + buildStateSystem(); + } catch (TmfTraceException e) { + e.printStackTrace(); + } + + /* Refresh the project, so it can pick up new files that got created. */ + try { + if (fResource != null) { + fResource.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); } + } catch (CoreException e) { + e.printStackTrace(); + } + } + if (signal.getTrace() == this) { + /* the signal is for this trace or experiment */ + if (getNbEvents() == 0) { + return; } + + final TmfTimeRange timeRange = new TmfTimeRange(getStartTime(), TmfTimestamp.BIG_CRUNCH); + final TmfTraceRangeUpdatedSignal rangeUpdatedsignal = new TmfTraceRangeUpdatedSignal(this, this, timeRange); + + // Broadcast in separate thread to prevent deadlock + new Thread() { + @Override + public void run() { + broadcast(rangeUpdatedsignal); + } + }.start(); + return; } } /** - * Hook for special processing by the concrete class (called by getNextEvent()) - * - * @param event + * Signal handler for the TmfTraceRangeUpdatedSignal signal + * + * @param signal The incoming signal + * @since 2.0 */ - protected void processEvent(final ITmfEvent event) { - // Do nothing by default + @TmfSignalHandler + public void traceRangeUpdated(final TmfTraceRangeUpdatedSignal signal) { + if (signal.getTrace() == this) { + getIndexer().buildIndex(getNbEvents(), signal.getRange(), false); + } + } + + /** + * Signal handler for the TmfTimeSynchSignal signal + * + * @param signal The incoming signal + * @since 2.0 + */ + @TmfSignalHandler + public void synchToTime(final TmfTimeSynchSignal signal) { + if (signal.getCurrentTime().compareTo(fStartTime) >= 0 && signal.getCurrentTime().compareTo(fEndTime) <= 0) { + fCurrentTime = signal.getCurrentTime(); + } + } + + /** + * Signal handler for the TmfRangeSynchSignal signal + * + * @param signal The incoming signal + * @since 2.0 + */ + @TmfSignalHandler + public void synchToRange(final TmfRangeSynchSignal signal) { + if (signal.getCurrentTime().compareTo(fStartTime) >= 0 && signal.getCurrentTime().compareTo(fEndTime) <= 0) { + fCurrentTime = signal.getCurrentTime(); + } + if (signal.getCurrentRange().getIntersection(getTimeRange()) != null) { + fCurrentRange = signal.getCurrentRange().getIntersection(getTimeRange()); + } } // ------------------------------------------------------------------------ @@ -590,8 +829,10 @@ public abstract class TmfTrace extends TmfEventProvider */ @Override @SuppressWarnings("nls") - public String toString() { - return "[TmfTrace (" + getName() + ")]"; + public synchronized String toString() { + return "TmfTrace [fPath=" + fPath + ", fCacheSize=" + fCacheSize + + ", fNbEvents=" + fNbEvents + ", fStartTime=" + fStartTime + + ", fEndTime=" + fEndTime + ", fStreamingInterval=" + fStreamingInterval + "]"; } }