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
;
69 // The cache page size AND checkpoints interval
70 protected int fIndexPageSize
;
72 // The set of event stream checkpoints (for random access)
73 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
75 // The number of events collected
76 protected long fNbEvents
= 0;
78 // The time span of the event stream
79 private TmfTimeRange fTimeRange
= new TmfTimeRange(TmfTimestamp
.BigBang
, TmfTimestamp
.BigBang
);
81 // ------------------------------------------------------------------------
83 // ------------------------------------------------------------------------
87 * @throws FileNotFoundException
89 protected TmfTrace(String name
, Class
<T
> type
, String path
) throws FileNotFoundException
{
90 this(name
, type
, path
, DEFAULT_CACHE_SIZE
);
96 * @throws FileNotFoundException
98 protected TmfTrace(String name
, Class
<T
> type
, String path
, int cacheSize
) throws FileNotFoundException
{
100 int sep
= path
.lastIndexOf(File
.separator
);
101 String simpleName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
104 fIndexPageSize
= (cacheSize
> 0) ? cacheSize
: DEFAULT_CACHE_SIZE
;
108 * @see java.lang.Object#clone()
110 @SuppressWarnings("unchecked")
112 public TmfTrace
<T
> clone() throws CloneNotSupportedException
{
113 TmfTrace
<T
> clone
= (TmfTrace
<T
>) super.clone();
114 clone
.fCheckpoints
= (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
115 clone
.fTimeRange
= new TmfTimeRange(fTimeRange
);
119 // ------------------------------------------------------------------------
121 // ------------------------------------------------------------------------
124 * @return the trace path
126 public String
getPath() {
131 // * @return the trace name
134 // public String getName() {
139 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
141 public long getNbEvents() {
146 * @return the size of the cache
148 public int getCacheSize() {
149 return fIndexPageSize
;
153 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
155 public TmfTimeRange
getTimeRange() {
160 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
162 public TmfTimestamp
getStartTime() {
163 return fTimeRange
.getStartTime();
167 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
169 public TmfTimestamp
getEndTime() {
170 return fTimeRange
.getEndTime();
173 @SuppressWarnings("unchecked")
174 public Vector
<TmfCheckpoint
> getCheckpoints() {
175 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
178 // ------------------------------------------------------------------------
180 // ------------------------------------------------------------------------
182 protected void setTimeRange(TmfTimeRange range
) {
186 protected void setStartTime(TmfTimestamp startTime
) {
187 fTimeRange
= new TmfTimeRange(startTime
, fTimeRange
.getEndTime());
190 protected void setEndTime(TmfTimestamp endTime
) {
191 fTimeRange
= new TmfTimeRange(fTimeRange
.getStartTime(), endTime
);
194 // ------------------------------------------------------------------------
196 // ------------------------------------------------------------------------
199 public ITmfContext
armRequest(ITmfDataRequest
<T
> request
) {
200 if (request
instanceof ITmfEventRequest
<?
>) {
201 return seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
203 return seekEvent(request
.getIndex());
207 * Return the next piece of data based on the context supplied. The context
208 * would typically be updated for the subsequent read.
213 @SuppressWarnings("unchecked")
215 public T
getNext(ITmfContext context
) {
216 if (context
instanceof TmfContext
) {
217 return (T
) getNextEvent((TmfContext
) context
);
222 // ------------------------------------------------------------------------
224 // ------------------------------------------------------------------------
227 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
229 public TmfContext
seekEvent(TmfTimestamp timestamp
) {
231 if (timestamp
== null) {
232 timestamp
= TmfTimestamp
.BigBang
;
235 // First, find the right checkpoint
236 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
238 // In the very likely case that the checkpoint was not found, bsearch
239 // returns its negated would-be location (not an offset...). From that
240 // index, we can then position the stream and get the event.
242 index
= Math
.max(0, -(index
+ 2));
245 // Position the stream at the checkpoint
246 ITmfLocation
<?
> location
;
247 synchronized (fCheckpoints
) {
248 if (fCheckpoints
.size() > 0) {
249 if (index
>= fCheckpoints
.size()) {
250 index
= fCheckpoints
.size() - 1;
252 location
= fCheckpoints
.elementAt(index
).getLocation();
258 TmfContext context
= seekLocation(location
);
259 context
.setRank(index
* fIndexPageSize
);
261 // And locate the event
262 TmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
263 TmfEvent event
= getNextEvent(nextEventContext
);
264 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
265 context
.setLocation(nextEventContext
.getLocation().clone());
266 context
.updateRank(1);
267 event
= getNextEvent(nextEventContext
);
274 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
276 public TmfContext
seekEvent(long rank
) {
278 // Position the stream at the previous checkpoint
279 int index
= (int) rank
/ fIndexPageSize
;
280 ITmfLocation
<?
> location
;
281 synchronized (fCheckpoints
) {
282 if (fCheckpoints
.size() == 0) {
286 if (index
>= fCheckpoints
.size()) {
287 index
= fCheckpoints
.size() - 1;
289 location
= fCheckpoints
.elementAt(index
).getLocation();
293 TmfContext context
= seekLocation(location
);
294 long pos
= index
* fIndexPageSize
;
295 context
.setRank(pos
);
298 TmfEvent event
= getNextEvent(context
);
299 while (event
!= null && ++pos
< rank
) {
300 event
= getNextEvent(context
);
308 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
310 public synchronized TmfEvent
getNextEvent(TmfContext context
) {
311 // parseEvent() does not update the context
312 TmfEvent event
= parseEvent(context
);
314 context
.setLocation(getCurrentLocation());
315 context
.updateRank(1);
322 * Hook for "special" processing by the concrete class
323 * (called by getNextEvent())
327 protected void processEvent(TmfEvent event
) {
328 // Do nothing by default
332 * To be implemented by the concrete class
334 public abstract TmfContext
seekLocation(ITmfLocation
<?
> location
);
335 public abstract ITmfLocation
<?
> getCurrentLocation();
336 public abstract TmfEvent
parseEvent(TmfContext context
);
338 // ------------------------------------------------------------------------
340 // ------------------------------------------------------------------------
343 * @see java.lang.Object#toString()
346 public String
toString() {
347 return "[TmfTrace (" + getName() + ")]";
350 // ------------------------------------------------------------------------
352 // ------------------------------------------------------------------------
355 * The purpose of the index is to perform a pass over the trace and collect
356 * basic information that can be later used to rapidly access a trace events.
358 * The information collected:
359 * - fCheckpoints, the list of evenly separated checkpoints (timestamp + location)
360 * - fTimeRange, the trace time span
361 * - fNbEvents, the number of events in the trace
363 * NOTE: Doesn't work for streaming traces.
366 private IndexingJob job
;
368 // Indicates that an indexing job is already running
369 private boolean fIndexing
= false;
370 private Boolean fIndexed
= false;
372 public void indexTrace(boolean waitForCompletion
) {
373 synchronized (this) {
374 if (fIndexed
|| fIndexing
) {
380 job
= new IndexingJob("Indexing " + getName());
383 if (waitForCompletion
) {
386 } catch (InterruptedException e
) {
392 private class IndexingJob
extends Job
{
394 public IndexingJob(String name
) {
399 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
402 protected IStatus
run(IProgressMonitor monitor
) {
404 monitor
.beginTask("Indexing " + getName(), IProgressMonitor
.UNKNOWN
);
407 TmfTimestamp startTime
= null;
408 TmfTimestamp lastTime
= null;
411 fCheckpoints
= new Vector
<TmfCheckpoint
>();
414 // Position the trace at the beginning
415 TmfContext context
= seekLocation(null);
416 ITmfLocation
<?
> location
= context
.getLocation().clone();
418 // Get the first event
419 TmfEvent event
= getNextEvent(context
);
421 startTime
= new TmfTimestamp(event
.getTimestamp());
425 while (event
!= null) {
426 lastTime
= event
.getTimestamp();
427 if ((nbEvents
++ % fIndexPageSize
) == 0) {
428 lastTime
= new TmfTimestamp(event
.getTimestamp());
429 fCheckpoints
.add(new TmfCheckpoint(lastTime
, location
));
433 // Check monitor *after* fCheckpoints has been updated
434 if (monitor
.isCanceled()) {
436 return Status
.CANCEL_STATUS
;
440 // We will need this location at the next iteration
441 if ((nbEvents
% fIndexPageSize
) == 0) {
442 location
= context
.getLocation().clone();
445 event
= getNextEvent(context
);
450 fNbEvents
= nbEvents
;
451 fTimeRange
= new TmfTimeRange(startTime
, lastTime
);
455 notifyListeners(fTimeRange
);
459 return Status
.OK_STATUS
;
463 protected void notifyListeners(TmfTimeRange range
) {
464 broadcast(new TmfTraceUpdatedSignal(this, this, range
));