1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2012 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.
44 * It should be sufficient to extend this class and provide implementations for
45 * <code>getCurrentLocation()</code> and <code>seekLocation()</code>, as well
46 * as a proper parser, to have a working concrete implementation.
48 public abstract class TmfTrace
<T
extends ITmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
<T
> {
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
55 * The default number of events in an index page. Can be used as block size.
57 public static final int DEFAULT_INDEX_PAGE_SIZE
= 1000;
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
63 // The resource used for persistent properties for this trace
64 private IResource fResource
;
70 * The cache page size AND checkpoints interval
72 protected int fIndexPageSize
= DEFAULT_INDEX_PAGE_SIZE
;
74 // The set of event stream checkpoints
75 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
77 // The number of events collected
78 protected long fNbEvents
= 0;
80 // The time span of the event stream
81 private ITmfTimestamp fStartTime
= TmfTimestamp
.BIG_CRUNCH
;
82 private ITmfTimestamp fEndTime
= TmfTimestamp
.BIG_BANG
;
85 * The trace streaming interval (0 = no streaming)
87 protected long fStreamingInterval
= 0;
89 // ------------------------------------------------------------------------
91 // ------------------------------------------------------------------------
94 * The default, parameterless, constructor
101 * The standard constructor (non-streaming trace)
103 * @param name the trace display name
104 * @param type the trace event type
105 * @param path the trace path
106 * @param pageSize the trace index page size
107 * @throws FileNotFoundException
109 protected TmfTrace(final IResource resource
, final Class
<T
> type
, final String path
, final int indexPageSize
) throws FileNotFoundException
{
110 this(resource
, type
, path
, 0, indexPageSize
);
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 * @throws FileNotFoundException
122 protected TmfTrace(final IResource resource
, final Class
<T
> type
, final String path
, final long interval
, final int indexPageSize
) throws FileNotFoundException
125 fStreamingInterval
= interval
;
126 fIndexPageSize
= (indexPageSize
> 0) ? indexPageSize
: DEFAULT_INDEX_PAGE_SIZE
;
127 initialize(resource
, path
, type
);
133 * @param trace the original trace
135 public TmfTrace(final ITmfTrace
<T
> trace
) throws FileNotFoundException
{
138 throw new IllegalArgumentException();
139 fStreamingInterval
= getStreamingInterval();
140 fIndexPageSize
= getIndexPageSize();
141 initialize(trace
.getResource(), trace
.getPath(), trace
.getType());
145 // ------------------------------------------------------------------------
146 // ITmfTrace - Initializers
147 // ------------------------------------------------------------------------
153 * @throws FileNotFoundException
155 protected void initialize(final IResource resource
, final String path
, final Class
<T
> type
) throws FileNotFoundException
{
156 fResource
= resource
;
158 String traceName
= (resource
!= null) ? resource
.getName() : null;
159 // If no display name was provided, extract it from the trace path
160 if (traceName
== null)
162 final int sep
= path
.lastIndexOf(Path
.SEPARATOR
);
163 traceName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
166 traceName
= ""; //$NON-NLS-1$
168 super.init(traceName
, type
);
172 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
175 public void initTrace(final IResource resource
, final String path
, final Class
<T
> type
) throws FileNotFoundException
{
176 initialize(resource
, path
, type
);
181 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
184 public boolean validate(final IProject project
, final String path
) {
185 final File file
= new File(path
);
186 return file
.exists();
189 // ------------------------------------------------------------------------
190 // ITmfTrace - Basic getters
191 // ------------------------------------------------------------------------
194 * @see org.eclipse.linuxtools.tmf.core.component.TmfDataProvider#getType()
197 @SuppressWarnings("unchecked")
198 public Class
<T
> getType() {
199 return (Class
<T
>) super.getType();
203 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
206 public IResource
getResource() {
211 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getPath()
214 public String
getPath() {
218 // ------------------------------------------------------------------------
219 // ITmfTrace - Trace characteristics getters
220 // ------------------------------------------------------------------------
223 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getNbEvents()
226 public long getNbEvents() {
231 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getTimeRange()
234 public TmfTimeRange
getTimeRange() {
235 return new TmfTimeRange(fStartTime
, fEndTime
);
239 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getStartTime()
242 public ITmfTimestamp
getStartTime() {
243 return new TmfTimestamp(fStartTime
);
247 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getEndTime()
250 public ITmfTimestamp
getEndTime() {
251 return new TmfTimestamp(fEndTime
);
254 // ------------------------------------------------------------------------
255 // ITmfTrace - Seek operations (returning a reading context)
256 // ------------------------------------------------------------------------
259 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
262 public ITmfContext
seekEvent(final ITmfTimestamp timestamp
) {
264 // A null timestamp indicates to seek the first event
265 if (timestamp
== null)
266 return seekLocation(null);
268 // Find the checkpoint at or before the requested timestamp.
269 // In the very likely event that the timestamp is not at a checkpoint
270 // boundary, bsearch will return index = (- (insertion point + 1)).
271 // It is then trivial to compute the index of the previous checkpoint.
272 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
274 index
= Math
.max(0, -(index
+ 2));
277 // Position the trace at the checkpoint
278 final ITmfContext context
= seekCheckpoint(index
);
280 // And locate the requested event context
281 final ITmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
282 ITmfEvent event
= getNextEvent(nextEventContext
);
283 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
284 context
.setLocation(nextEventContext
.getLocation().clone());
285 context
.increaseRank();
286 event
= getNextEvent(nextEventContext
);
292 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long)
295 public ITmfContext
seekEvent(final long rank
) {
297 // A rank <= 0 indicates to seek the first event
299 return seekLocation(null);
301 // Find the checkpoint at or before the requested rank.
302 final int index
= (int) rank
/ fIndexPageSize
;
303 final ITmfContext context
= seekCheckpoint(index
);
305 // And locate the requested event context
306 long pos
= context
.getRank();
308 ITmfEvent event
= getNextEvent(context
);
309 while (event
!= null && ++pos
< rank
) {
310 event
= getNextEvent(context
);
318 * Position the trace at the given checkpoint
320 * @param index the checkpoint index
321 * @return the corresponding context
323 private ITmfContext
seekCheckpoint(int index
) {
324 ITmfLocation
<?
> location
;
325 synchronized (fCheckpoints
) {
326 if (!fCheckpoints
.isEmpty()) {
327 if (index
>= fCheckpoints
.size()) {
328 index
= fCheckpoints
.size() - 1;
330 location
= fCheckpoints
.elementAt(index
).getLocation();
335 final ITmfContext context
= seekLocation(location
);
336 context
.setRank(index
* fIndexPageSize
);
340 // ------------------------------------------------------------------------
341 // ITmfTrace - Read operations (returning an actual event)
342 // ------------------------------------------------------------------------
345 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
348 public synchronized ITmfEvent
getNextEvent(final ITmfContext context
) {
349 // parseEvent() does not update the context
350 final ITmfEvent event
= parseEvent(context
);
352 updateIndex(context
, context
.getRank(), event
.getTimestamp());
353 context
.setLocation(getCurrentLocation());
354 context
.increaseRank();
361 * Hook for special processing by the concrete class (called by
366 protected void processEvent(final ITmfEvent event
) {
367 // Do nothing by default
370 protected synchronized void updateIndex(final ITmfContext context
, final long rank
, final ITmfTimestamp timestamp
) {
371 if (fStartTime
.compareTo(timestamp
, false) > 0) {
372 fStartTime
= timestamp
;
374 if (fEndTime
.compareTo(timestamp
, false) < 0) {
375 fEndTime
= timestamp
;
377 if (context
.hasValidRank()) {
378 if (fNbEvents
<= rank
) {
379 fNbEvents
= rank
+ 1;
381 // Build the index as we go along
382 if ((rank
% fIndexPageSize
) == 0) {
383 // Determine the table position
384 final long position
= rank
/ fIndexPageSize
;
385 // Add new entry at proper location (if empty)
386 if (fCheckpoints
.size() == position
) {
387 final ITmfLocation
<?
> location
= context
.getLocation().clone();
388 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
389 // System.out.println(getName() + "[" + (fCheckpoints.size() + "] " + timestamp + ", " + location.toString());
395 // ------------------------------------------------------------------------
396 // ITmfTrace - indexing
397 // ------------------------------------------------------------------------
400 * The index is a list of contexts that point to events at regular interval
401 * (rank-wise) in the trace. After it is built, the index can be used to
402 * quickly access any event by rank or timestamp.
404 * fIndexPageSize holds the event interval (default INDEX_PAGE_SIZE).
407 @SuppressWarnings({ "unchecked" })
408 protected void indexTrace(final boolean waitForCompletion
) {
410 // The monitoring job
411 final Job job
= new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
414 protected IStatus
run(final IProgressMonitor monitor
) {
415 while (!monitor
.isCanceled()) {
418 } catch (final InterruptedException e
) {
419 return Status
.OK_STATUS
;
423 return Status
.OK_STATUS
;
428 // Clear the checkpoints
429 fCheckpoints
.clear();
431 // Build a background request for all the trace data. The index is
432 // updated as we go by getNextEvent().
433 final ITmfEventRequest
<ITmfEvent
> request
= new TmfEventRequest
<ITmfEvent
>(ITmfEvent
.class,
434 TmfTimeRange
.ETERNITY
,
435 TmfDataRequest
.ALL_DATA
, fIndexPageSize
, ITmfDataRequest
.ExecutionType
.BACKGROUND
)
438 ITmfTimestamp startTime
= null;
439 ITmfTimestamp lastTime
= null;
442 public void handleData(final ITmfEvent event
) {
443 super.handleData(event
);
445 final ITmfTimestamp timestamp
= event
.getTimestamp();
446 if (startTime
== null) {
447 startTime
= timestamp
.clone();
449 lastTime
= timestamp
.clone();
451 // Update the trace status at regular intervals
452 if ((getNbRead() % fIndexPageSize
) == 0) {
459 public void handleSuccess() {
464 public void handleCompleted() {
466 super.handleCompleted();
469 private synchronized void updateTraceStatus() {
470 final int nbRead
= getNbRead();
472 fStartTime
= startTime
;
480 // Submit the request and wait for completion if required
481 sendRequest((ITmfDataRequest
<T
>) request
);
482 if (waitForCompletion
) {
484 request
.waitForCompletion();
485 } catch (final InterruptedException e
) {
490 private void notifyListeners() {
491 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime
, fEndTime
)));
494 // ------------------------------------------------------------------------
496 // ------------------------------------------------------------------------
498 @SuppressWarnings("unchecked")
499 public Vector
<TmfCheckpoint
> getCheckpoints() {
500 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
503 // ------------------------------------------------------------------------
505 // ------------------------------------------------------------------------
507 protected void setTimeRange(final TmfTimeRange range
) {
508 fStartTime
= range
.getStartTime();
509 fEndTime
= range
.getEndTime();
512 protected void setStartTime(final ITmfTimestamp startTime
) {
513 fStartTime
= startTime
;
516 protected void setEndTime(final ITmfTimestamp endTime
) {
520 // ------------------------------------------------------------------------
522 // ------------------------------------------------------------------------
525 public ITmfContext
armRequest(final ITmfDataRequest
<T
> request
) {
526 if (request
instanceof ITmfEventRequest
<?
>
527 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime())
528 && request
.getIndex() == 0) {
529 final ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
530 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
534 return seekEvent(request
.getIndex());
538 * Return the next piece of data based on the context supplied. The context
539 * would typically be updated for the subsequent read.
542 * @return the event referred to by context
544 @SuppressWarnings("unchecked")
546 public T
getNext(final ITmfContext context
) {
547 if (context
instanceof TmfContext
)
548 return (T
) getNextEvent(context
);
553 // ------------------------------------------------------------------------
555 // ------------------------------------------------------------------------
560 * @see java.lang.Object#toString()
563 @SuppressWarnings("nls")
564 public String
toString() {
565 return "[TmfTrace (" + getName() + ")]";
568 // ------------------------------------------------------------------------
569 // ITmfTrace - Trace TBD getters
570 // ------------------------------------------------------------------------
573 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getStreamingInterval()
576 public long getStreamingInterval() {
577 return fStreamingInterval
;
581 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize()
584 public int getIndexPageSize() {
585 return fIndexPageSize
;