1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.trace
;
16 import java
.io
.FileNotFoundException
;
17 import java
.util
.Collections
;
18 import java
.util
.Vector
;
20 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
21 import org
.eclipse
.core
.runtime
.IStatus
;
22 import org
.eclipse
.core
.runtime
.Status
;
23 import org
.eclipse
.core
.runtime
.jobs
.Job
;
24 import org
.eclipse
.linuxtools
.tmf
.component
.TmfEventProvider
;
25 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
26 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
27 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
28 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfDataRequest
;
29 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfEventRequest
;
30 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfTraceUpdatedSignal
;
33 * <b><u>TmfTrace</u></b>
35 * Abstract implementation of ITmfTrace. It should be sufficient to extend this
36 * class and provide implementation for <code>getCurrentLocation()</code> and
37 * <code>seekLocation()</code>, as well as a proper parser, to have a working
38 * concrete implementation.
40 * Note: The notion of event rank is still under heavy discussion. Although
41 * used by the Events View and probably useful in the general case, there
42 * is no easy way to implement it for LTTng (actually a strong case is being
43 * made that this is useless).
45 * That it is not supported by LTTng does by no mean indicate that it is not
46 * useful for (just about) every other tracing tool. Therefore, this class
47 * provides a minimal (and partial) implementation of rank. However, the current
48 * implementation should not be relied on in the general case.
50 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
52 public abstract class TmfTrace
<T
extends TmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
, Cloneable
{
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
58 // The default number of events to cache
59 // TODO: Make the DEFAULT_CACHE_SIZE a preference
60 public static final int DEFAULT_CACHE_SIZE
= 1000;
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
67 private final String fPath
;
70 private final String fName
;
72 // The cache page size AND checkpoints interval
73 protected int fIndexPageSize
;
75 // The set of event stream checkpoints (for random access)
76 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
78 // The number of events collected
79 protected long fNbEvents
= 0;
81 // The time span of the event stream
82 private TmfTimeRange fTimeRange
= new TmfTimeRange(TmfTimestamp
.BigBang
, TmfTimestamp
.BigBang
);
84 // ------------------------------------------------------------------------
86 // ------------------------------------------------------------------------
90 * @throws FileNotFoundException
92 protected TmfTrace(Class
<T
> type
, String path
) throws FileNotFoundException
{
93 this(type
, path
, DEFAULT_CACHE_SIZE
);
99 * @throws FileNotFoundException
101 protected TmfTrace(Class
<T
> type
, String path
, int cacheSize
) throws FileNotFoundException
{
103 int sep
= path
.lastIndexOf(File
.separator
);
104 fName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
106 fIndexPageSize
= (cacheSize
> 0) ? cacheSize
: DEFAULT_CACHE_SIZE
;
110 * @see java.lang.Object#clone()
112 @SuppressWarnings("unchecked")
114 public TmfTrace
<T
> clone() throws CloneNotSupportedException
{
115 TmfTrace
<T
> clone
= (TmfTrace
<T
>) super.clone();
116 clone
.fCheckpoints
= (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
117 clone
.fTimeRange
= new TmfTimeRange(fTimeRange
);
121 // ------------------------------------------------------------------------
123 // ------------------------------------------------------------------------
126 * @return the trace path
128 public String
getPath() {
133 * @return the trace name
136 public String
getName() {
141 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
143 public long getNbEvents() {
148 * @return the size of the cache
150 public int getCacheSize() {
151 return fIndexPageSize
;
155 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
157 public TmfTimeRange
getTimeRange() {
162 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
164 public TmfTimestamp
getStartTime() {
165 return fTimeRange
.getStartTime();
169 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
171 public TmfTimestamp
getEndTime() {
172 return fTimeRange
.getEndTime();
175 @SuppressWarnings("unchecked")
176 public Vector
<TmfCheckpoint
> getCheckpoints() {
177 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
180 // ------------------------------------------------------------------------
182 // ------------------------------------------------------------------------
184 protected void setTimeRange(TmfTimeRange range
) {
188 protected void setStartTime(TmfTimestamp startTime
) {
189 fTimeRange
= new TmfTimeRange(startTime
, fTimeRange
.getEndTime());
192 protected void setEndTime(TmfTimestamp endTime
) {
193 fTimeRange
= new TmfTimeRange(fTimeRange
.getStartTime(), endTime
);
196 // ------------------------------------------------------------------------
198 // ------------------------------------------------------------------------
201 public ITmfContext
armRequest(ITmfDataRequest
<T
> request
) {
202 if (request
instanceof ITmfEventRequest
<?
>) {
203 return seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
205 return seekEvent(request
.getIndex());
209 * Return the next piece of data based on the context supplied. The context
210 * would typically be updated for the subsequent read.
215 @SuppressWarnings("unchecked")
217 public T
getNext(ITmfContext context
) {
218 if (context
instanceof TmfContext
) {
219 return (T
) getNextEvent((TmfContext
) context
);
224 // ------------------------------------------------------------------------
226 // ------------------------------------------------------------------------
229 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
231 public TmfContext
seekEvent(TmfTimestamp timestamp
) {
233 if (timestamp
== null) {
234 timestamp
= TmfTimestamp
.BigBang
;
237 // First, find the right checkpoint
238 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
240 // In the very likely case that the checkpoint was not found, bsearch
241 // returns its negated would-be location (not an offset...). From that
242 // index, we can then position the stream and get the event.
244 index
= Math
.max(0, -(index
+ 2));
247 // Position the stream at the checkpoint
248 ITmfLocation
<?
> location
;
249 synchronized (fCheckpoints
) {
250 if (fCheckpoints
.size() > 0) {
251 if (index
>= fCheckpoints
.size()) {
252 index
= fCheckpoints
.size() - 1;
254 location
= fCheckpoints
.elementAt(index
).getLocation();
260 TmfContext context
= seekLocation(location
);
261 context
.setRank(index
* fIndexPageSize
);
263 // And locate the event
264 TmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
265 TmfEvent event
= getNextEvent(nextEventContext
);
266 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
267 context
.setLocation(nextEventContext
.getLocation().clone());
268 context
.updateRank(1);
269 event
= getNextEvent(nextEventContext
);
276 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
278 public TmfContext
seekEvent(long rank
) {
280 // Position the stream at the previous checkpoint
281 int index
= (int) rank
/ fIndexPageSize
;
282 ITmfLocation
<?
> location
;
283 synchronized (fCheckpoints
) {
284 if (fCheckpoints
.size() == 0) {
288 if (index
>= fCheckpoints
.size()) {
289 index
= fCheckpoints
.size() - 1;
291 location
= fCheckpoints
.elementAt(index
).getLocation();
295 TmfContext context
= seekLocation(location
);
296 long pos
= index
* fIndexPageSize
;
297 context
.setRank(pos
);
300 TmfEvent event
= getNextEvent(context
);
301 while (event
!= null && ++pos
< rank
) {
302 event
= getNextEvent(context
);
310 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
312 public synchronized TmfEvent
getNextEvent(TmfContext context
) {
313 // parseEvent() does not update the context
314 TmfEvent event
= parseEvent(context
);
316 context
.setLocation(getCurrentLocation());
317 context
.updateRank(1);
324 * Hook for "special" processing by the concrete class
325 * (called by getNextEvent())
329 protected void processEvent(TmfEvent event
) {
330 // Do nothing by default
334 * To be implemented by the concrete class
336 public abstract TmfContext
seekLocation(ITmfLocation
<?
> location
);
337 public abstract ITmfLocation
<?
> getCurrentLocation();
338 public abstract TmfEvent
parseEvent(TmfContext context
);
340 // ------------------------------------------------------------------------
342 // ------------------------------------------------------------------------
345 * @see java.lang.Object#toString()
348 public String
toString() {
349 return "[TmfTrace (" + fName
+ ")]";
352 // ------------------------------------------------------------------------
354 // ------------------------------------------------------------------------
357 * The purpose of the index is to perform a pass over the trace and collect
358 * basic information that can be later used to rapidly access a trace events.
360 * The information collected:
361 * - fCheckpoints, the list of evenly separated checkpoints (timestamp + location)
362 * - fTimeRange, the trace time span
363 * - fNbEvents, the number of events in the trace
365 * NOTE: Doesn't work for streaming traces.
368 private IndexingJob job
;
370 // Indicates that an indexing job is already running
371 private boolean fIndexing
= false;
372 private Boolean fIndexed
= false;
374 public void indexTrace(boolean waitForCompletion
) {
375 synchronized (this) {
376 if (fIndexed
|| fIndexing
) {
382 job
= new IndexingJob("Indexing " + fName
);
385 if (waitForCompletion
) {
388 } catch (InterruptedException e
) {
394 private class IndexingJob
extends Job
{
396 public IndexingJob(String name
) {
401 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
404 protected IStatus
run(IProgressMonitor monitor
) {
406 monitor
.beginTask("Indexing " + fName
, IProgressMonitor
.UNKNOWN
);
409 TmfTimestamp startTime
= null;
410 TmfTimestamp lastTime
= null;
413 fCheckpoints
= new Vector
<TmfCheckpoint
>();
416 // Position the trace at the beginning
417 TmfContext context
= seekLocation(null);
418 ITmfLocation
<?
> location
= context
.getLocation().clone();
420 // Get the first event
421 TmfEvent event
= getNextEvent(context
);
423 startTime
= new TmfTimestamp(event
.getTimestamp());
427 while (event
!= null) {
428 lastTime
= event
.getTimestamp();
429 if ((nbEvents
++ % fIndexPageSize
) == 0) {
430 lastTime
= new TmfTimestamp(event
.getTimestamp());
431 fCheckpoints
.add(new TmfCheckpoint(lastTime
, location
));
432 fNbEvents
= nbEvents
;
433 fTimeRange
= new TmfTimeRange(startTime
, lastTime
);
434 notifyListeners(new TmfTimeRange(startTime
, lastTime
));
438 // Check monitor *after* fCheckpoints has been updated
439 if (monitor
.isCanceled()) {
441 return Status
.CANCEL_STATUS
;
445 // We will need this location at the next iteration
446 if ((nbEvents
% fIndexPageSize
) == 0) {
447 location
= context
.getLocation().clone();
450 event
= getNextEvent(context
);
455 fNbEvents
= nbEvents
;
456 fTimeRange
= new TmfTimeRange(startTime
, lastTime
);
460 notifyListeners(new TmfTimeRange(startTime
, lastTime
));
464 return Status
.OK_STATUS
;
468 protected void notifyListeners(TmfTimeRange range
) {
469 broadcast(new TmfTraceUpdatedSignal(this, this, range
));