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 class and provide implementation for
43 * <code>getCurrentLocation()</code> and <code>seekLocation()</code>, as well as a proper parser, to have a working
44 * concrete implementation.
46 public abstract class TmfTrace
<T
extends ITmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
<T
> {
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
53 * The default number of events in an index page. Can be used as block size.
55 public static final int DEFAULT_INDEX_PAGE_SIZE
= 1000;
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
65 * The cache page size AND checkpoints interval
67 protected int fIndexPageSize
= DEFAULT_INDEX_PAGE_SIZE
;
69 // The set of event stream checkpoints
70 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
72 // The number of events collected
73 protected long fNbEvents
= 0;
75 // The time span of the event stream
76 private ITmfTimestamp fStartTime
= TmfTimestamp
.BIG_CRUNCH
;
77 private ITmfTimestamp fEndTime
= TmfTimestamp
.BIG_BANG
;
80 * The trace streaming interval (0 = no streaming)
82 protected long fStreamingInterval
= 0;
84 // The resource used for persistent properties for this trace
85 private IResource fResource
;
87 // ------------------------------------------------------------------------
89 // ------------------------------------------------------------------------
92 * The default, parameterless, constructor
99 * The standard constructor (non-streaming trace)
101 * @param name the trace display name
102 * @param type the trace event type
103 * @param path the trace path
104 * @param pageSize the trace index page size
105 * @param indexTrace whether to start indexing the trace or not
106 * @throws FileNotFoundException
108 protected TmfTrace(final IResource resource
, final Class
<T
> type
, final String path
, final int indexPageSize
,
109 final boolean indexTrace
) throws FileNotFoundException
{
110 this(resource
, 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 IResource resource
, final Class
<T
> type
, final String path
, final long interval
,
124 final int indexPageSize
, final boolean indexTrace
) throws FileNotFoundException
{
126 initTrace(resource
, path
, type
);
127 fStreamingInterval
= interval
;
128 fIndexPageSize
= (indexPageSize
> 0) ? indexPageSize
: DEFAULT_INDEX_PAGE_SIZE
;
136 * @param trace the original trace
138 public TmfTrace(final ITmfTrace
<T
> trace
) throws FileNotFoundException
{
141 throw new IllegalArgumentException();
142 initTrace(trace
.getResource(), trace
.getPath(), trace
.getType());
143 fStreamingInterval
= getStreamingInterval();
144 fIndexPageSize
= getIndexPageSize();
149 // ------------------------------------------------------------------------
152 // ------------------------------------------------------------------------
155 // * @see java.lang.Object#clone()
158 // @SuppressWarnings("unchecked")
159 // public TmfTrace<T> clone() {
160 // TmfTrace<T> clone = null;
162 // clone = (TmfTrace<T>) super.clone();
163 // // clone.fTrace = fTrace;
164 // // clone.fRank = fRank;
165 // // clone.fTimestamp = fTimestamp != null ? fTimestamp.clone() : null;
166 // // clone.fSource = fSource;
167 // // clone.fType = fType != null ? fType.clone() : null;
168 // // clone.fContent = fContent != null ? fContent.clone() : null;
169 // // clone.fReference = fReference;
170 // } catch (final CloneNotSupportedException e) {
175 // ------------------------------------------------------------------------
176 // ITmfTrace - initializers
177 // ------------------------------------------------------------------------
183 * org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#initTrace(java.lang.String
184 * , java.lang.String, java.lang.Class)
187 public void initTrace(final IResource resource
, final String path
, final Class
<T
> type
) throws FileNotFoundException
{
188 fResource
= resource
;
190 String traceName
= (resource
!= null) ? resource
.getName() : null;
191 // If no display name was provided, extract it from the trace path
192 if (traceName
== null)
194 final int sep
= path
.lastIndexOf(Path
.SEPARATOR
);
195 traceName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
197 traceName
= ""; //$NON-NLS-1$
198 super.init(traceName
, type
);
205 * org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.
206 * core.resources.IProject, java.lang.String)
209 public boolean validate(final IProject project
, final String path
) {
210 final File file
= new File(path
);
211 return file
.exists();
214 // ------------------------------------------------------------------------
215 // ITmfTrace - accessors
216 // ------------------------------------------------------------------------
219 * @return the trace path
222 public Class
<T
> getType() {
227 * @return the trace path
230 public String
getPath() {
237 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
240 public IResource
getResource() {
247 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
250 public synchronized long getNbEvents() {
257 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
260 public TmfTimeRange
getTimeRange() {
261 return new TmfTimeRange(fStartTime
, fEndTime
);
267 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
270 public ITmfTimestamp
getStartTime() {
271 return fStartTime
.clone();
277 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
280 public ITmfTimestamp
getEndTime() {
281 return fEndTime
.clone();
287 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
290 public long getStreamingInterval() {
291 return fStreamingInterval
;
297 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize()
300 public int getIndexPageSize() {
301 return fIndexPageSize
;
304 // ------------------------------------------------------------------------
305 // ITmfTrace - indexing
306 // ------------------------------------------------------------------------
309 * The index is a list of contexts that point to events at regular interval
310 * (rank-wise) in the trace. After it is built, the index can be used to
311 * quickly access any event by rank or timestamp.
313 * fIndexPageSize holds the event interval (default INDEX_PAGE_SIZE).
317 @SuppressWarnings({ "unchecked" })
318 public void indexTrace(final boolean waitForCompletion
) {
320 // The monitoring job
321 final Job job
= new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
324 protected IStatus
run(final IProgressMonitor monitor
) {
325 while (!monitor
.isCanceled())
328 } catch (final InterruptedException e
) {
329 return Status
.OK_STATUS
;
332 return Status
.OK_STATUS
;
337 // Clear the checkpoints
338 fCheckpoints
.clear();
340 // Build a background request for all the trace data. The index is
341 // updated as we go by getNextEvent().
342 final ITmfEventRequest
<ITmfEvent
> request
= new TmfEventRequest
<ITmfEvent
>(ITmfEvent
.class,
343 TmfTimeRange
.ETERNITY
,
344 TmfDataRequest
.ALL_DATA
, fIndexPageSize
, ITmfDataRequest
.ExecutionType
.BACKGROUND
)
347 ITmfTimestamp startTime
= null;
348 ITmfTimestamp lastTime
= null;
351 public void handleData(final ITmfEvent event
) {
352 super.handleData(event
);
354 final ITmfTimestamp timestamp
= event
.getTimestamp();
355 if (startTime
== null)
356 startTime
= timestamp
.clone();
357 lastTime
= timestamp
.clone();
359 // Update the trace status at regular intervals
360 if ((getNbRead() % fIndexPageSize
) == 0)
366 public void handleSuccess() {
371 public void handleCompleted() {
373 super.handleCompleted();
376 private synchronized void updateTraceStatus() {
377 final int nbRead
= getNbRead();
379 fStartTime
= startTime
;
387 // Submit the request and wait for completion if required
388 sendRequest((ITmfDataRequest
<T
>) request
);
389 if (waitForCompletion
)
391 request
.waitForCompletion();
392 } catch (final InterruptedException e
) {
396 private void notifyListeners() {
397 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime
, fEndTime
)));
400 // ------------------------------------------------------------------------
401 // ITmfTrace - seek operations
402 // ------------------------------------------------------------------------
408 * org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse
409 * .linuxtools.tmf.core.event.ITmfTimestamp)
412 public ITmfContext
seekEvent(final ITmfTimestamp ts
) {
414 ITmfTimestamp timestamp
= ts
;
415 if (timestamp
== null)
416 timestamp
= TmfTimestamp
.BIG_BANG
;
418 // First, find the right checkpoint
419 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
421 // In the very likely case that the checkpoint was not found, bsearch
422 // returns its negated would-be location (not an offset...). From that
423 // index, we can then position the stream and get the event.
425 index
= Math
.max(0, -(index
+ 2));
427 // Position the stream at the checkpoint
428 ITmfLocation
<?
> location
;
429 synchronized (fCheckpoints
) {
430 if (!fCheckpoints
.isEmpty()) {
431 if (index
>= fCheckpoints
.size())
432 index
= fCheckpoints
.size() - 1;
433 location
= fCheckpoints
.elementAt(index
).getLocation();
437 final ITmfContext context
= seekLocation(location
);
438 context
.setRank(index
* fIndexPageSize
);
440 // And locate the event
441 final ITmfContext nextEventContext
= context
.clone(); // Must use
445 ITmfEvent event
= getNextEvent(nextEventContext
);
446 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
447 context
.setLocation(nextEventContext
.getLocation().clone());
448 context
.increaseRank();
449 event
= getNextEvent(nextEventContext
);
458 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long)
461 public ITmfContext
seekEvent(final long rank
) {
463 // Position the stream at the previous checkpoint
464 int index
= (int) rank
/ fIndexPageSize
;
465 ITmfLocation
<?
> location
;
466 synchronized (fCheckpoints
) {
467 if (fCheckpoints
.isEmpty())
470 if (index
>= fCheckpoints
.size())
471 index
= fCheckpoints
.size() - 1;
472 location
= fCheckpoints
.elementAt(index
).getLocation();
476 final ITmfContext context
= seekLocation(location
);
477 long pos
= index
* fIndexPageSize
;
478 context
.setRank(pos
);
481 ITmfEvent event
= getNextEvent(context
);
482 while (event
!= null && ++pos
< rank
)
483 event
= getNextEvent(context
);
489 // ------------------------------------------------------------------------
491 // ------------------------------------------------------------------------
493 // ------------------------------------------------------------------------
495 // ------------------------------------------------------------------------
497 @SuppressWarnings("unchecked")
498 public Vector
<TmfCheckpoint
> getCheckpoints() {
499 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
502 // ------------------------------------------------------------------------
504 // ------------------------------------------------------------------------
506 protected void setTimeRange(final TmfTimeRange range
) {
507 fStartTime
= range
.getStartTime();
508 fEndTime
= range
.getEndTime();
511 protected void setStartTime(final ITmfTimestamp startTime
) {
512 fStartTime
= startTime
;
515 protected void setEndTime(final ITmfTimestamp endTime
) {
519 // ------------------------------------------------------------------------
521 // ------------------------------------------------------------------------
524 public ITmfContext
armRequest(final ITmfDataRequest
<T
> request
) {
525 if (request
instanceof ITmfEventRequest
<?
>
526 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime())
527 && request
.getIndex() == 0) {
528 final ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
529 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
533 return seekEvent(request
.getIndex());
537 * Return the next piece of data based on the context supplied. The context
538 * would typically be updated for the subsequent read.
541 * @return the event referred to by context
543 @SuppressWarnings("unchecked")
545 public T
getNext(final ITmfContext context
) {
546 if (context
instanceof TmfContext
)
547 return (T
) getNextEvent(context
);
551 // ------------------------------------------------------------------------
553 // ------------------------------------------------------------------------
558 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
559 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
562 public synchronized ITmfEvent
getNextEvent(final ITmfContext context
) {
563 // parseEvent() does not update the context
564 final ITmfEvent event
= parseEvent(context
);
566 updateIndex(context
, context
.getRank(), event
.getTimestamp());
567 context
.setLocation(getCurrentLocation());
568 context
.increaseRank();
574 protected synchronized void updateIndex(final ITmfContext context
, final long rank
, final ITmfTimestamp timestamp
) {
575 if (fStartTime
.compareTo(timestamp
, false) > 0)
576 fStartTime
= timestamp
;
577 if (fEndTime
.compareTo(timestamp
, false) < 0)
578 fEndTime
= timestamp
;
579 if (context
.hasValidRank()) {
580 if (fNbEvents
<= rank
)
581 fNbEvents
= rank
+ 1;
582 // Build the index as we go along
583 if ((rank
% fIndexPageSize
) == 0) {
584 // Determine the table position
585 final long position
= rank
/ fIndexPageSize
;
586 // Add new entry at proper location (if empty)
587 if (fCheckpoints
.size() == position
) {
588 final ITmfLocation
<?
> location
= context
.getLocation().clone();
589 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
590 // System.out.println(getName() + "[" + (fCheckpoints.size()
591 // - 1) + "] " + timestamp + ", " + location.toString());
598 * Hook for special processing by the concrete class (called by
603 protected void processEvent(final ITmfEvent event
) {
604 // Do nothing by default
607 // ------------------------------------------------------------------------
609 // ------------------------------------------------------------------------
614 * @see java.lang.Object#toString()
617 @SuppressWarnings("nls")
618 public String
toString() {
619 return "[TmfTrace (" + getName() + ")]";