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
.TmfCoalescedEventRequest
;
29 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
30 import org
.eclipse
.linuxtools
.tmf
.request
.TmfEventRequest
;
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 for by the Events View and probably useful in then 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). Therefore, this is a minimal and partial
44 * implementation and rank should not be relied upon in the general case (i.e.
45 * it was hacked to work for the Events View).
47 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
49 public abstract class TmfTrace
<T
extends TmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
{
51 // ------------------------------------------------------------------------
53 // ------------------------------------------------------------------------
55 // The default number of events to cache
56 // TODO: Make the DEFAULT_CACHE_SIZE a preference
57 public static final int DEFAULT_CACHE_SIZE
= 1000;
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
64 private final String fPath
;
67 private final String fName
;
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 // ------------------------------------------------------------------------
88 * @throws FileNotFoundException
90 protected TmfTrace(Class
<T
> type
, String path
, int cacheSize
) throws FileNotFoundException
{
92 int sep
= path
.lastIndexOf(File
.separator
);
93 fName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
95 fIndexPageSize
= (cacheSize
> 0) ? cacheSize
: DEFAULT_CACHE_SIZE
;
100 * @throws FileNotFoundException
102 protected TmfTrace(Class
<T
> type
, String path
) throws FileNotFoundException
{
103 this(type
, path
, DEFAULT_CACHE_SIZE
);
106 // ------------------------------------------------------------------------
108 // ------------------------------------------------------------------------
111 * @return the trace path
113 public String
getPath() {
118 * @return the trace name
121 public String
getName() {
126 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
128 public long getNbEvents() {
133 * @return the size of the cache
135 public int getCacheSize() {
136 return fIndexPageSize
;
140 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
142 public TmfTimeRange
getTimeRange() {
147 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
149 public TmfTimestamp
getStartTime() {
150 return fTimeRange
.getStartTime();
154 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
156 public TmfTimestamp
getEndTime() {
157 return fTimeRange
.getEndTime();
160 public Vector
<TmfCheckpoint
> getCheckpoints() {
164 // ------------------------------------------------------------------------
166 // ------------------------------------------------------------------------
168 protected void setTimeRange(TmfTimeRange range
) {
172 protected void setStartTime(TmfTimestamp startTime
) {
173 fTimeRange
= new TmfTimeRange(startTime
, fTimeRange
.getEndTime());
176 protected void setEndTime(TmfTimestamp endTime
) {
177 fTimeRange
= new TmfTimeRange(fTimeRange
.getStartTime(), endTime
);
180 // ------------------------------------------------------------------------
182 // ------------------------------------------------------------------------
185 public ITmfContext
armRequest(TmfDataRequest
<T
> request
) {
186 if (request
instanceof TmfEventRequest
<?
>) {
187 return seekEvent(((TmfEventRequest
<T
>) request
).getRange().getStartTime());
189 if (request
instanceof TmfCoalescedEventRequest
<?
>) {
190 return seekEvent(((TmfCoalescedEventRequest
<T
>) request
).getRange().getStartTime());
196 * Return the next piece of data based on the context supplied. The context
197 * would typically be updated for the subsequent read.
202 @SuppressWarnings("unchecked")
204 public T
getNext(ITmfContext context
) {
205 if (context
instanceof TmfContext
) {
206 return (T
) getNextEvent((TmfContext
) context
);
211 // ------------------------------------------------------------------------
213 // ------------------------------------------------------------------------
216 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
218 public TmfContext
seekEvent(TmfTimestamp timestamp
) {
220 if (timestamp
== null) {
221 timestamp
= TmfTimestamp
.BigBang
;
224 // First, find the right checkpoint
225 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
227 // In the very likely case that the checkpoint was not found, bsearch
228 // returns its negated would-be location (not an offset...). From that
229 // index, we can then position the stream and get the event.
231 index
= Math
.max(0, -(index
+ 2));
234 // Position the stream at the checkpoint
235 ITmfLocation
<?
> location
;
236 synchronized (fCheckpoints
) {
237 if (fCheckpoints
.size() > 0) {
238 if (index
>= fCheckpoints
.size()) {
239 index
= fCheckpoints
.size() - 1;
241 location
= fCheckpoints
.elementAt(index
).getLocation();
247 TmfContext context
= seekLocation(location
);
248 context
.setRank(index
* fIndexPageSize
);
250 // And locate the event
251 TmfContext nextEventContext
= new TmfContext(context
);
252 TmfEvent event
= getNextEvent(nextEventContext
);
253 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
254 context
.setLocation(nextEventContext
.getLocation().clone());
255 context
.updateRank(1);
256 event
= getNextEvent(nextEventContext
);
263 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
265 public TmfContext
seekEvent(long rank
) {
267 // Position the stream at the previous checkpoint
268 int index
= (int) rank
/ fIndexPageSize
;
269 ITmfLocation
<?
> location
;
270 synchronized (fCheckpoints
) {
271 if (fCheckpoints
.size() == 0) {
275 if (index
>= fCheckpoints
.size()) {
276 index
= fCheckpoints
.size() - 1;
278 location
= fCheckpoints
.elementAt(index
).getLocation();
282 TmfContext context
= seekLocation(location
);
283 long pos
= index
* fIndexPageSize
;
284 context
.setRank(pos
);
287 TmfEvent event
= getNextEvent(context
);
288 while (event
!= null && ++pos
< rank
) {
289 event
= getNextEvent(context
);
293 return new TmfContext(context
.getLocation(), context
.getRank());
297 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
299 public synchronized TmfEvent
getNextEvent(TmfContext context
) {
300 // parseEvent() does not update the context
301 TmfEvent event
= parseEvent(context
);
303 context
.setLocation(getCurrentLocation());
304 context
.updateRank(1);
311 * Hook for "special" processing by the concrete class
312 * (called by getNextEvent())
316 public void processEvent(TmfEvent event
) {
317 // Do nothing by default
321 * To be implemented by the concrete class
323 public abstract TmfContext
seekLocation(ITmfLocation
<?
> location
);
324 public abstract ITmfLocation
<?
> getCurrentLocation();
325 public abstract TmfEvent
parseEvent(TmfContext context
);
327 // ------------------------------------------------------------------------
329 // ------------------------------------------------------------------------
332 * @see java.lang.Object#toString()
335 public String
toString() {
336 return "[TmfTrace (" + fName
+ "]";
339 // ------------------------------------------------------------------------
341 // ------------------------------------------------------------------------
344 * The purpose of the index is to keep the information needed to rapidly
345 * access a trace event based on its timestamp or rank.
347 * NOTE: As it is, doesn't work for streaming traces.
350 private IndexingJob job
;
352 // Indicates that an indexing job is already running
353 private Object fIndexingLock
= new Object();
354 private boolean fIndexing
= false;
355 private Boolean fIndexed
= false;
357 public void indexTrace(boolean waitForCompletion
) {
358 synchronized (fIndexingLock
) {
359 if (fIndexed
|| fIndexing
) {
365 job
= new IndexingJob("Indexing " + fName
);
368 if (waitForCompletion
) {
371 } catch (InterruptedException e
) {
377 private class IndexingJob
extends Job
{
379 public IndexingJob(String name
) {
384 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
387 protected IStatus
run(IProgressMonitor monitor
) {
389 monitor
.beginTask("Indexing " + fName
, IProgressMonitor
.UNKNOWN
);
392 TmfTimestamp startTime
= null;
393 TmfTimestamp lastTime
= null;
396 fCheckpoints
= new Vector
<TmfCheckpoint
>();
399 // Position the trace at the beginning
400 TmfContext context
= seekLocation(null);
401 ITmfLocation
<?
> location
= context
.getLocation().clone();
403 // Get the first event
404 TmfEvent event
= getNextEvent(context
);
406 startTime
= new TmfTimestamp(event
.getTimestamp());
410 while (event
!= null) {
411 lastTime
= event
.getTimestamp();
412 if ((nbEvents
++ % fIndexPageSize
) == 0) {
413 lastTime
= new TmfTimestamp(event
.getTimestamp());
414 fCheckpoints
.add(new TmfCheckpoint(lastTime
, location
.clone()));
415 fNbEvents
= nbEvents
;
416 fTimeRange
= new TmfTimeRange(startTime
, lastTime
);
417 notifyListeners(new TmfTimeRange(startTime
, lastTime
));
421 // Check monitor *after* fCheckpoints has been updated
422 if (monitor
.isCanceled()) {
424 return Status
.CANCEL_STATUS
;
428 // We will need this location at the next iteration
429 if ((nbEvents
% fIndexPageSize
) == 0) {
430 location
= context
.getLocation().clone();
433 event
= getNextEvent(context
);
438 fNbEvents
= nbEvents
;
439 fTimeRange
= new TmfTimeRange(startTime
, lastTime
);
443 notifyListeners(new TmfTimeRange(startTime
, lastTime
));
447 return Status
.OK_STATUS
;
451 protected void notifyListeners(TmfTimeRange range
) {
452 broadcast(new TmfTraceUpdatedSignal(this, this, range
));