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 * Francois Chouinard - Updated as per TMF Trace Model 1.0
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
17 import java
.io
.FileNotFoundException
;
18 import java
.util
.Collections
;
19 import java
.util
.Vector
;
21 import org
.eclipse
.core
.resources
.IProject
;
22 import org
.eclipse
.core
.resources
.IResource
;
23 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
24 import org
.eclipse
.core
.runtime
.IStatus
;
25 import org
.eclipse
.core
.runtime
.Path
;
26 import org
.eclipse
.core
.runtime
.Status
;
27 import org
.eclipse
.core
.runtime
.jobs
.Job
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.component
.TmfEventProvider
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfDataRequest
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfEventRequest
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
40 * <b><u>TmfTrace</u></b>
42 * Abstract implementation of ITmfTrace. It should be sufficient to extend this
43 * class and provide implementation for <code>getCurrentLocation()</code> and
44 * <code>seekLocation()</code>, as well as a proper parser, to have a working
45 * concrete implementation.
47 public abstract class TmfTrace
<T
extends ITmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
<T
> {
49 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
54 * The default number of events in an index page. Can be used as block size.
56 public static final int DEFAULT_INDEX_PAGE_SIZE
= 1000;
58 // ------------------------------------------------------------------------
60 // ------------------------------------------------------------------------
66 * The cache page size AND checkpoints interval
68 protected int fIndexPageSize
= DEFAULT_INDEX_PAGE_SIZE
;
70 // The set of event stream checkpoints
71 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
73 // The number of events collected
74 protected long fNbEvents
= 0;
76 // The time span of the event stream
77 private ITmfTimestamp fStartTime
= TmfTimestamp
.BIG_CRUNCH
;
78 private ITmfTimestamp fEndTime
= TmfTimestamp
.BIG_BANG
;
81 * The trace streaming interval (0 = no streaming)
83 protected long fStreamingInterval
= 0;
85 // The resource used for persistent properties for this trace
86 private IResource fResource
;
88 // ------------------------------------------------------------------------
90 // ------------------------------------------------------------------------
93 * The default, parameterless, constructor
100 * The standard constructor (non-streaming trace)
102 * @param name the trace display name
103 * @param type the trace event type
104 * @param path the trace path
105 * @param pageSize the trace index page size
106 * @param indexTrace whether to start indexing the trace or not
107 * @throws FileNotFoundException
109 protected TmfTrace(final String name
, final Class
<T
> type
, final String path
, final int indexPageSize
, final boolean indexTrace
) throws FileNotFoundException
{
110 this(name
, type
, path
, 0, indexPageSize
, indexTrace
);
114 * The full constructor
116 * @param name the trace display name
117 * @param type the trace event type
118 * @param path the trace path
119 * @param pageSize the trace index page size
120 * @param indexTrace whether to start indexing the trace or not
121 * @throws FileNotFoundException
123 protected TmfTrace(final String name
, final Class
<T
> type
, final String path
, final long interval
, final int indexPageSize
, final boolean indexTrace
) throws FileNotFoundException
{
125 initTrace(name
, path
, type
);
126 fStreamingInterval
= interval
;
127 fIndexPageSize
= (indexPageSize
>0) ? indexPageSize
: DEFAULT_INDEX_PAGE_SIZE
;
135 * @param trace the original trace
137 @SuppressWarnings("unchecked")
138 public TmfTrace(final ITmfTrace
<T
> trace
) throws FileNotFoundException
{
141 throw new IllegalArgumentException();
142 initTrace(getName(), getPath(), (Class
<T
>) getType());
143 fStreamingInterval
= getStreamingInterval();
144 fIndexPageSize
= getIndexPageSize();
148 // // ------------------------------------------------------------------------
150 // // ------------------------------------------------------------------------
153 // * @see java.lang.Object#clone()
156 // @SuppressWarnings("unchecked")
157 // public TmfTrace<T> clone() {
158 // TmfTrace<T> clone = null;
160 // clone = (TmfTrace<T>) super.clone();
161 // // clone.fTrace = fTrace;
162 // // clone.fRank = fRank;
163 // // clone.fTimestamp = fTimestamp != null ? fTimestamp.clone() : null;
164 // // clone.fSource = fSource;
165 // // clone.fType = fType != null ? fType.clone() : null;
166 // // clone.fContent = fContent != null ? fContent.clone() : null;
167 // // clone.fReference = fReference;
168 // } catch (final CloneNotSupportedException e) {
173 // ------------------------------------------------------------------------
174 // ITmfTrace - initializers
175 // ------------------------------------------------------------------------
178 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#initTrace(java.lang.String, java.lang.String, java.lang.Class)
181 public void initTrace(final String name
, final String path
, final Class
<T
> type
) throws FileNotFoundException
{
183 String traceName
= name
;
184 // If no display name was provided, extract it from the trace path
185 if (traceName
== null)
187 final int sep
= path
.lastIndexOf(Path
.SEPARATOR
);
188 traceName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
190 traceName
= ""; //$NON-NLS-1$
191 super.init(traceName
, type
);
195 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
198 public boolean validate(final IProject project
, final String path
) {
199 final File file
= new File(path
);
200 return file
.exists();
205 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#setResource(org.eclipse.core.resources.IResource)
208 public void setResource(final IResource resource
) {
209 fResource
= resource
;
212 // ------------------------------------------------------------------------
213 // ITmfTrace - accessors
214 // ------------------------------------------------------------------------
217 * @return the trace path
220 public String
getPath() {
226 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
229 public IResource
getResource() {
234 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
237 public synchronized long getNbEvents() {
242 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
245 public TmfTimeRange
getTimeRange() {
246 return new TmfTimeRange(fStartTime
, fEndTime
);
250 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
253 public ITmfTimestamp
getStartTime() {
254 return fStartTime
.clone();
258 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
261 public ITmfTimestamp
getEndTime() {
262 return fEndTime
.clone();
266 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
269 public long getStreamingInterval() {
270 return fStreamingInterval
;
274 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize()
277 public int getIndexPageSize() {
278 return fIndexPageSize
;
281 // ------------------------------------------------------------------------
282 // ITmfTrace - indexing
283 // ------------------------------------------------------------------------
286 * The index is a list of contexts that point to events at regular interval
287 * (rank-wise) in the trace. After it is built, the index can be used to
288 * quickly access any event by rank or timestamp.
290 * fIndexPageSize holds the event interval (default INDEX_PAGE_SIZE).
294 @SuppressWarnings({ "unchecked" })
295 public void indexTrace(final boolean waitForCompletion
) {
297 // The monitoring job
298 final Job job
= new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
300 protected IStatus
run(final IProgressMonitor monitor
) {
301 while (!monitor
.isCanceled())
304 } catch (final InterruptedException e
) {
305 return Status
.OK_STATUS
;
308 return Status
.OK_STATUS
;
313 // Clear the checkpoints
314 fCheckpoints
.clear();
316 // Build a background request for all the trace data. The index is
317 // updated as we go by getNextEvent().
318 final ITmfEventRequest
<ITmfEvent
> request
= new TmfEventRequest
<ITmfEvent
>(ITmfEvent
.class, TmfTimeRange
.ETERNITY
,
319 TmfDataRequest
.ALL_DATA
, fIndexPageSize
, ITmfDataRequest
.ExecutionType
.BACKGROUND
)
321 ITmfTimestamp startTime
= null;
322 ITmfTimestamp lastTime
= null;
325 public void handleData(final ITmfEvent event
) {
326 super.handleData(event
);
328 final ITmfTimestamp timestamp
= event
.getTimestamp();
329 if (startTime
== null)
330 startTime
= timestamp
.clone();
331 lastTime
= timestamp
.clone();
333 // Update the trace status at regular intervals
334 if ((getNbRead() % fIndexPageSize
) == 0)
340 public void handleSuccess() {
345 public void handleCompleted() {
347 super.handleCompleted();
350 private synchronized void updateTraceStatus() {
351 final int nbRead
= getNbRead();
353 fStartTime
= startTime
;
361 // Submit the request and wait for completion if required
362 sendRequest((ITmfDataRequest
<T
>) request
);
363 if (waitForCompletion
)
365 request
.waitForCompletion();
366 } catch (final InterruptedException e
) {
370 private void notifyListeners() {
371 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime
, fEndTime
)));
374 // ------------------------------------------------------------------------
375 // ITmfTrace - seek operations
376 // ------------------------------------------------------------------------
379 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
382 public ITmfContext
seekEvent(final ITmfTimestamp ts
) {
384 ITmfTimestamp timestamp
= ts
;
385 if (timestamp
== null)
386 timestamp
= TmfTimestamp
.BIG_BANG
;
388 // First, find the right checkpoint
389 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
391 // In the very likely case that the checkpoint was not found, bsearch
392 // returns its negated would-be location (not an offset...). From that
393 // index, we can then position the stream and get the event.
395 index
= Math
.max(0, -(index
+ 2));
397 // Position the stream at the checkpoint
398 ITmfLocation
<?
> location
;
399 synchronized (fCheckpoints
) {
400 if (!fCheckpoints
.isEmpty()) {
401 if (index
>= fCheckpoints
.size())
402 index
= fCheckpoints
.size() - 1;
403 location
= fCheckpoints
.elementAt(index
).getLocation();
407 final ITmfContext context
= seekLocation(location
);
408 context
.setRank(index
* fIndexPageSize
);
410 // And locate the event
411 final ITmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
412 ITmfEvent event
= getNextEvent(nextEventContext
);
413 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
414 context
.setLocation(nextEventContext
.getLocation().clone());
415 context
.increaseRank();
416 event
= getNextEvent(nextEventContext
);
423 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long)
426 public ITmfContext
seekEvent(final long rank
) {
428 // Position the stream at the previous checkpoint
429 int index
= (int) rank
/ fIndexPageSize
;
430 ITmfLocation
<?
> location
;
431 synchronized (fCheckpoints
) {
432 if (fCheckpoints
.isEmpty())
435 if (index
>= fCheckpoints
.size())
436 index
= fCheckpoints
.size() - 1;
437 location
= fCheckpoints
.elementAt(index
).getLocation();
441 final ITmfContext context
= seekLocation(location
);
442 long pos
= index
* fIndexPageSize
;
443 context
.setRank(pos
);
446 ITmfEvent event
= getNextEvent(context
);
447 while (event
!= null && ++pos
< rank
)
448 event
= getNextEvent(context
);
454 // ------------------------------------------------------------------------
456 // ------------------------------------------------------------------------
458 // ------------------------------------------------------------------------
460 // ------------------------------------------------------------------------
462 @SuppressWarnings("unchecked")
463 public Vector
<TmfCheckpoint
> getCheckpoints() {
464 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
468 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
471 * @param timestamp the requested event timestamp
472 * @return the corresponding event rank
475 public long getRank(final ITmfTimestamp timestamp
) {
476 final ITmfContext context
= seekEvent(timestamp
);
477 return context
.getRank();
480 // ------------------------------------------------------------------------
482 // ------------------------------------------------------------------------
484 protected void setTimeRange(final TmfTimeRange range
) {
485 fStartTime
= range
.getStartTime();
486 fEndTime
= range
.getEndTime();
489 protected void setStartTime(final ITmfTimestamp startTime
) {
490 fStartTime
= startTime
;
493 protected void setEndTime(final ITmfTimestamp endTime
) {
497 // ------------------------------------------------------------------------
499 // ------------------------------------------------------------------------
502 public ITmfContext
armRequest(final ITmfDataRequest
<T
> request
) {
503 if (request
instanceof ITmfEventRequest
<?
>
504 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime()) && request
.getIndex() == 0) {
505 final ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
506 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
510 return seekEvent(request
.getIndex());
514 * Return the next piece of data based on the context supplied. The context would typically be updated for the
518 * @return the event referred to by context
520 @SuppressWarnings("unchecked")
522 public T
getNext(final ITmfContext context
) {
523 if (context
instanceof TmfContext
)
524 return (T
) getNextEvent(context
);
528 // ------------------------------------------------------------------------
530 // ------------------------------------------------------------------------
536 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
537 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
540 public synchronized ITmfEvent
getNextEvent(final ITmfContext context
) {
541 // parseEvent() does not update the context
542 final ITmfEvent event
= parseEvent(context
);
544 updateIndex(context
, context
.getRank(), event
.getTimestamp());
545 context
.setLocation(getCurrentLocation());
546 context
.increaseRank();
552 protected synchronized void updateIndex(final ITmfContext context
, final long rank
, final ITmfTimestamp timestamp
) {
553 if (fStartTime
.compareTo(timestamp
, false) > 0)
554 fStartTime
= timestamp
;
555 if (fEndTime
.compareTo(timestamp
, false) < 0)
556 fEndTime
= timestamp
;
557 if (context
.hasValidRank()) {
558 if (fNbEvents
<= rank
)
559 fNbEvents
= rank
+ 1;
560 // Build the index as we go along
561 if ((rank
% fIndexPageSize
) == 0) {
562 // Determine the table position
563 final long position
= rank
/ fIndexPageSize
;
564 // Add new entry at proper location (if empty)
565 if (fCheckpoints
.size() == position
) {
566 final ITmfLocation
<?
> location
= context
.getLocation().clone();
567 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
568 // System.out.println(getName() + "[" + (fCheckpoints.size()
569 // - 1) + "] " + timestamp + ", " + location.toString());
576 * Hook for special processing by the concrete class (called by getNextEvent())
580 protected void processEvent(final ITmfEvent event
) {
581 // Do nothing by default
584 // ------------------------------------------------------------------------
586 // ------------------------------------------------------------------------
589 * @see java.lang.Object#toString()
592 @SuppressWarnings("nls")
593 public String
toString() {
594 return "[TmfTrace (" + getName() + ")]";