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
= 50000;
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(String name
, Class
<T
> type
, String path
, int indexPageSize
, 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(String name
, Class
<T
> type
, String path
, long interval
, int indexPageSize
, 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(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 (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(String name
, String path
, 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 int sep
= path
.lastIndexOf(Path
.SEPARATOR
);
188 traceName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
190 traceName
= ""; //$NON-NLS-1$
193 super.init(traceName
, type
);
197 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
200 public boolean validate(IProject project
, String path
) {
201 File file
= new File(path
);
202 return file
.exists();
207 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#setResource(org.eclipse.core.resources.IResource)
210 public void setResource(IResource resource
) {
211 fResource
= resource
;
214 // ------------------------------------------------------------------------
215 // ITmfTrace - accessors
216 // ------------------------------------------------------------------------
219 * @return the trace path
222 public String
getPath() {
228 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
231 public IResource
getResource() {
236 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
239 public synchronized long getNbEvents() {
244 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
247 public TmfTimeRange
getTimeRange() {
248 return new TmfTimeRange(fStartTime
, fEndTime
);
252 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
255 public ITmfTimestamp
getStartTime() {
256 return fStartTime
.clone();
260 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
263 public ITmfTimestamp
getEndTime() {
264 return fEndTime
.clone();
268 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
271 public long getStreamingInterval() {
272 return fStreamingInterval
;
276 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize()
279 public int getIndexPageSize() {
280 return fIndexPageSize
;
283 // ------------------------------------------------------------------------
284 // ITmfTrace - indexing
285 // ------------------------------------------------------------------------
288 * The index is a list of contexts that point to events at regular interval
289 * (rank-wise) in the trace. After it is built, the index can be used to
290 * quickly access any event by rank or timestamp.
292 * fIndexPageSize holds the event interval (default INDEX_PAGE_SIZE).
296 @SuppressWarnings({ "unchecked" })
297 public void indexTrace(boolean waitForCompletion
) {
299 // The monitoring job
300 final Job job
= new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
302 protected IStatus
run(IProgressMonitor monitor
) {
303 while (!monitor
.isCanceled()) {
306 } catch (InterruptedException e
) {
307 return Status
.OK_STATUS
;
311 return Status
.OK_STATUS
;
316 // Clear the checkpoints
317 fCheckpoints
.clear();
319 // Build a background request for all the trace data. The index is
320 // updated as we go by getNextEvent().
321 ITmfEventRequest
<ITmfEvent
> request
= new TmfEventRequest
<ITmfEvent
>(ITmfEvent
.class, TmfTimeRange
.ETERNITY
,
322 TmfDataRequest
.ALL_DATA
, fIndexPageSize
, ITmfDataRequest
.ExecutionType
.BACKGROUND
)
324 ITmfTimestamp startTime
= null;
325 ITmfTimestamp lastTime
= null;
328 public void handleData(ITmfEvent event
) {
329 super.handleData(event
);
331 ITmfTimestamp timestamp
= event
.getTimestamp();
332 if (startTime
== null)
333 startTime
= timestamp
.clone();
334 lastTime
= timestamp
.clone();
336 // Update the trace status at regular intervals
337 if ((getNbRead() % fIndexPageSize
) == 0) {
344 public void handleSuccess() {
349 public void handleCompleted() {
351 super.handleCompleted();
354 private synchronized void updateTraceStatus() {
355 int nbRead
= getNbRead();
357 fStartTime
= startTime
;
365 // Submit the request and wait for completion if required
366 sendRequest((ITmfDataRequest
<T
>) request
);
367 if (waitForCompletion
)
369 request
.waitForCompletion();
370 } catch (InterruptedException e
) {
374 private void notifyListeners() {
375 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime
, fEndTime
)));
378 // ------------------------------------------------------------------------
379 // ITmfTrace - seek operations
380 // ------------------------------------------------------------------------
383 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
386 public ITmfContext
seekEvent(ITmfTimestamp ts
) {
388 ITmfTimestamp timestamp
= ts
;
389 if (timestamp
== null) {
390 timestamp
= TmfTimestamp
.BIG_BANG
;
393 // First, find the right checkpoint
394 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
396 // In the very likely case that the checkpoint was not found, bsearch
397 // returns its negated would-be location (not an offset...). From that
398 // index, we can then position the stream and get the event.
400 index
= Math
.max(0, -(index
+ 2));
403 // Position the stream at the checkpoint
404 ITmfLocation
<?
> location
;
405 synchronized (fCheckpoints
) {
406 if (!fCheckpoints
.isEmpty()) {
407 if (index
>= fCheckpoints
.size()) {
408 index
= fCheckpoints
.size() - 1;
410 location
= fCheckpoints
.elementAt(index
).getLocation();
415 ITmfContext context
= seekLocation(location
);
416 context
.setRank(index
* fIndexPageSize
);
418 // And locate the event
419 ITmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
420 ITmfEvent event
= getNextEvent(nextEventContext
);
421 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
422 context
.setLocation(nextEventContext
.getLocation().clone());
423 context
.updateRank(1);
424 event
= getNextEvent(nextEventContext
);
431 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long)
434 public ITmfContext
seekEvent(long rank
) {
436 // Position the stream at the previous checkpoint
437 int index
= (int) rank
/ fIndexPageSize
;
438 ITmfLocation
<?
> location
;
439 synchronized (fCheckpoints
) {
440 if (fCheckpoints
.isEmpty()) {
443 if (index
>= fCheckpoints
.size()) {
444 index
= fCheckpoints
.size() - 1;
446 location
= fCheckpoints
.elementAt(index
).getLocation();
450 ITmfContext context
= seekLocation(location
);
451 long pos
= index
* fIndexPageSize
;
452 context
.setRank(pos
);
455 ITmfEvent event
= getNextEvent(context
);
456 while (event
!= null && ++pos
< rank
) {
457 event
= getNextEvent(context
);
464 // ------------------------------------------------------------------------
466 // ------------------------------------------------------------------------
468 // ------------------------------------------------------------------------
470 // ------------------------------------------------------------------------
472 @SuppressWarnings("unchecked")
473 public Vector
<TmfCheckpoint
> getCheckpoints() {
474 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
478 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
481 * @param timestamp the requested event timestamp
482 * @return the corresponding event rank
485 public long getRank(ITmfTimestamp timestamp
) {
486 ITmfContext context
= seekEvent(timestamp
);
487 return context
.getRank();
490 // ------------------------------------------------------------------------
492 // ------------------------------------------------------------------------
494 protected void setTimeRange(TmfTimeRange range
) {
495 fStartTime
= range
.getStartTime();
496 fEndTime
= range
.getEndTime();
499 protected void setStartTime(ITmfTimestamp startTime
) {
500 fStartTime
= startTime
;
503 protected void setEndTime(ITmfTimestamp endTime
) {
507 // ------------------------------------------------------------------------
509 // ------------------------------------------------------------------------
512 public ITmfContext
armRequest(ITmfDataRequest
<T
> request
) {
513 if (request
instanceof ITmfEventRequest
<?
>
514 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime()) && request
.getIndex() == 0) {
515 ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
516 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
520 return seekEvent(request
.getIndex());
524 * Return the next piece of data based on the context supplied. The context would typically be updated for the
528 * @return the event referred to by context
530 @SuppressWarnings("unchecked")
532 public T
getNext(ITmfContext context
) {
533 if (context
instanceof TmfContext
) {
534 return (T
) getNextEvent((TmfContext
) context
);
539 // ------------------------------------------------------------------------
541 // ------------------------------------------------------------------------
547 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
548 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
551 public synchronized ITmfEvent
getNextEvent(ITmfContext context
) {
552 // parseEvent() does not update the context
553 ITmfEvent event
= parseEvent(context
);
555 updateIndex(context
, context
.getRank(), event
.getTimestamp());
556 context
.setLocation(getCurrentLocation());
557 context
.updateRank(1);
563 protected synchronized void updateIndex(ITmfContext context
, long rank
, ITmfTimestamp timestamp
) {
564 if (fStartTime
.compareTo(timestamp
, false) > 0)
565 fStartTime
= timestamp
;
566 if (fEndTime
.compareTo(timestamp
, false) < 0)
567 fEndTime
= timestamp
;
568 if (context
.isValidRank()) {
569 if (fNbEvents
<= rank
)
570 fNbEvents
= rank
+ 1;
571 // Build the index as we go along
572 if ((rank
% fIndexPageSize
) == 0) {
573 // Determine the table position
574 long position
= rank
/ fIndexPageSize
;
575 // Add new entry at proper location (if empty)
576 if (fCheckpoints
.size() == position
) {
577 ITmfLocation
<?
> location
= context
.getLocation().clone();
578 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
579 // System.out.println(getName() + "[" + (fCheckpoints.size()
580 // - 1) + "] " + timestamp + ", " + location.toString());
587 * Hook for special processing by the concrete class (called by getNextEvent())
591 protected void processEvent(ITmfEvent event
) {
592 // Do nothing by default
595 // ------------------------------------------------------------------------
597 // ------------------------------------------------------------------------
600 * @see java.lang.Object#toString()
603 @SuppressWarnings("nls")
604 public String
toString() {
605 return "[TmfTrace (" + getName() + ")]";