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
.resources
.IProject
;
21 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
22 import org
.eclipse
.core
.runtime
.IStatus
;
23 import org
.eclipse
.core
.runtime
.Status
;
24 import org
.eclipse
.core
.runtime
.jobs
.Job
;
25 import org
.eclipse
.linuxtools
.tmf
.component
.TmfEventProvider
;
26 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
27 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
28 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
29 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfDataRequest
;
30 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfEventRequest
;
31 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
32 import org
.eclipse
.linuxtools
.tmf
.request
.TmfEventRequest
;
33 import org
.eclipse
.linuxtools
.tmf
.signal
.TmfTraceUpdatedSignal
;
36 * <b><u>TmfTrace</u></b>
38 * Abstract implementation of ITmfTrace. It should be sufficient to extend this class and provide implementation for
39 * <code>getCurrentLocation()</code> and <code>seekLocation()</code>, as well as a proper parser, to have a working
40 * concrete implementation.
42 * Note: The notion of event rank is still under heavy discussion. Although used by the Events View and probably useful
43 * in the general case, there is no easy way to implement it for LTTng (actually a strong case is being made that this
46 * That it is not supported by LTTng does by no mean indicate that it is not useful for (just about) every other tracing
47 * tool. Therefore, this class provides a minimal (and partial) implementation of rank. However, the current
48 * implementation should not be relied on in the general case.
50 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
52 public abstract class TmfTrace
<T
extends TmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
<T
>, Cloneable
{
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
58 // The default number of events to cache
59 // TODO: Make the DEFAULT_CACHE_SIZE a preference
60 public static final int DEFAULT_INDEX_PAGE_SIZE
= 50000;
62 // ------------------------------------------------------------------------
64 // ------------------------------------------------------------------------
72 // The cache page size AND checkpoints interval
73 protected int fIndexPageSize
= DEFAULT_INDEX_PAGE_SIZE
;
75 // The set of event stream checkpoints (for random access)
76 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
78 // The number of events collected
79 protected long fNbEvents
= 0;
81 // The time span of the event stream
82 private TmfTimestamp fStartTime
= TmfTimestamp
.BigCrunch
;
83 private TmfTimestamp fEndTime
= TmfTimestamp
.BigBang
;
85 // ------------------------------------------------------------------------
87 // ------------------------------------------------------------------------
94 public void initTrace(String path
, Class
<T
> eventType
) throws FileNotFoundException
{
95 initTrace(path
, eventType
, DEFAULT_INDEX_PAGE_SIZE
, false);
99 public void initTrace(String path
, Class
<T
> eventType
, int cacheSize
) throws FileNotFoundException
{
100 initTrace(path
, eventType
, cacheSize
, false);
104 public void initTrace(String path
, Class
<T
> eventType
, boolean indexTrace
) throws FileNotFoundException
{
105 initTrace(path
, eventType
, DEFAULT_INDEX_PAGE_SIZE
, indexTrace
);
109 public void initTrace(String path
, Class
<T
> eventType
, int cacheSize
, boolean indexTrace
) throws FileNotFoundException
{
112 fName
= ""; //$NON-NLS-1$
114 int sep
= path
.lastIndexOf(File
.separator
);
115 fName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
118 super.init(fName
, eventType
);
119 fIndexPageSize
= (cacheSize
> 0) ? cacheSize
: DEFAULT_INDEX_PAGE_SIZE
;
125 public boolean validate(IProject project
, String path
) {
126 File file
= new File(path
);
127 return file
.exists();
132 * @throws FileNotFoundException
134 protected TmfTrace(String name
, Class
<T
> type
, String path
) throws FileNotFoundException
{
135 this(name
, type
, path
, DEFAULT_INDEX_PAGE_SIZE
, true);
141 * @throws FileNotFoundException
143 protected TmfTrace(String name
, Class
<T
> type
, String path
, int cacheSize
) throws FileNotFoundException
{
144 this(name
, type
, path
, cacheSize
, true);
150 * @throws FileNotFoundException
152 protected TmfTrace(String name
, Class
<T
> type
, String path
, boolean indexTrace
) throws FileNotFoundException
{
153 this(name
, type
, path
, DEFAULT_INDEX_PAGE_SIZE
, indexTrace
);
160 * @throws FileNotFoundException
162 protected TmfTrace(String name
, Class
<T
> type
, String path
, int cacheSize
, boolean indexTrace
) throws FileNotFoundException
{
165 initTrace(path
, type
, cacheSize
, indexTrace
);
168 @SuppressWarnings("unchecked")
170 public TmfTrace
<T
> clone() throws CloneNotSupportedException
{
171 TmfTrace
<T
> clone
= (TmfTrace
<T
>) super.clone();
172 clone
.fCheckpoints
= fCheckpoints
;
173 clone
.fStartTime
= new TmfTimestamp(fStartTime
);
174 clone
.fEndTime
= new TmfTimestamp(fEndTime
);
178 // ------------------------------------------------------------------------
180 // ------------------------------------------------------------------------
183 * @return the trace path
186 public String
getPath() {
191 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
194 public long getNbEvents() {
199 * @return the size of the cache
202 public int getCacheSize() {
203 return fIndexPageSize
;
207 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
210 public TmfTimeRange
getTimeRange() {
211 return new TmfTimeRange(fStartTime
, fEndTime
);
215 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
218 public TmfTimestamp
getStartTime() {
223 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
226 public TmfTimestamp
getEndTime() {
230 @SuppressWarnings("unchecked")
231 public Vector
<TmfCheckpoint
> getCheckpoints() {
232 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
236 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
243 public long getRank(TmfTimestamp timestamp
) {
244 TmfContext context
= seekEvent(timestamp
);
245 return context
.getRank();
248 // ------------------------------------------------------------------------
250 // ------------------------------------------------------------------------
252 protected void setTimeRange(TmfTimeRange range
) {
253 fStartTime
= range
.getStartTime();
254 fEndTime
= range
.getEndTime();
257 protected void setStartTime(TmfTimestamp startTime
) {
258 fStartTime
= startTime
;
261 protected void setEndTime(TmfTimestamp endTime
) {
265 // ------------------------------------------------------------------------
267 // ------------------------------------------------------------------------
270 public ITmfContext
armRequest(ITmfDataRequest
<T
> request
) {
271 if (request
instanceof ITmfEventRequest
<?
>
272 && !TmfTimestamp
.BigBang
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime()) && request
.getIndex() == 0) {
273 ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
274 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
278 return seekEvent(request
.getIndex());
282 * Return the next piece of data based on the context supplied. The context would typically be updated for the
288 @SuppressWarnings("unchecked")
290 public T
getNext(ITmfContext context
) {
291 if (context
instanceof TmfContext
) {
292 return (T
) getNextEvent((TmfContext
) context
);
297 // ------------------------------------------------------------------------
299 // ------------------------------------------------------------------------
302 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
305 public TmfContext
seekEvent(TmfTimestamp timestamp
) {
307 if (timestamp
== null) {
308 timestamp
= TmfTimestamp
.BigBang
;
311 // First, find the right checkpoint
312 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
314 // In the very likely case that the checkpoint was not found, bsearch
315 // returns its negated would-be location (not an offset...). From that
316 // index, we can then position the stream and get the event.
318 index
= Math
.max(0, -(index
+ 2));
321 // Position the stream at the checkpoint
322 ITmfLocation
<?
> location
;
323 synchronized (fCheckpoints
) {
324 if (fCheckpoints
.size() > 0) {
325 if (index
>= fCheckpoints
.size()) {
326 index
= fCheckpoints
.size() - 1;
328 location
= fCheckpoints
.elementAt(index
).getLocation();
333 TmfContext context
= seekLocation(location
);
334 context
.setRank(index
* fIndexPageSize
);
336 // And locate the event
337 TmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
338 TmfEvent event
= getNextEvent(nextEventContext
);
339 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
340 context
.setLocation(nextEventContext
.getLocation().clone());
341 context
.updateRank(1);
342 event
= getNextEvent(nextEventContext
);
349 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
352 public TmfContext
seekEvent(long rank
) {
354 // Position the stream at the previous checkpoint
355 int index
= (int) rank
/ fIndexPageSize
;
356 ITmfLocation
<?
> location
;
357 synchronized (fCheckpoints
) {
358 if (fCheckpoints
.size() == 0) {
361 if (index
>= fCheckpoints
.size()) {
362 index
= fCheckpoints
.size() - 1;
364 location
= fCheckpoints
.elementAt(index
).getLocation();
368 TmfContext context
= seekLocation(location
);
369 long pos
= index
* fIndexPageSize
;
370 context
.setRank(pos
);
373 TmfEvent event
= getNextEvent(context
);
374 while (event
!= null && ++pos
< rank
) {
375 event
= getNextEvent(context
);
385 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
386 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
389 public synchronized TmfEvent
getNextEvent(TmfContext context
) {
390 // parseEvent() does not update the context
391 TmfEvent event
= parseEvent(context
);
393 updateIndex(context
, context
.getRank(), event
.getTimestamp());
394 context
.setLocation(getCurrentLocation());
395 context
.updateRank(1);
401 protected synchronized void updateIndex(ITmfContext context
, long rank
, TmfTimestamp timestamp
) {
402 if (fStartTime
.compareTo(timestamp
, false) > 0)
403 fStartTime
= timestamp
;
404 if (fEndTime
.compareTo(timestamp
, false) < 0)
405 fEndTime
= timestamp
;
406 if (context
.isValidRank()) {
407 if (fNbEvents
<= rank
)
408 fNbEvents
= rank
+ 1;
409 // Build the index as we go along
410 if ((rank
% fIndexPageSize
) == 0) {
411 // Determine the table position
412 long position
= rank
/ fIndexPageSize
;
413 // Add new entry at proper location (if empty)
414 if (fCheckpoints
.size() == position
) {
415 ITmfLocation
<?
> location
= context
.getLocation().clone();
416 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
417 // System.out.println(getName() + "[" + (fCheckpoints.size()
418 // - 1) + "] " + timestamp + ", " + location.toString());
425 * Hook for special processing by the concrete class (called by getNextEvent())
429 protected void processEvent(TmfEvent event
) {
430 // Do nothing by default
433 // ------------------------------------------------------------------------
435 // ------------------------------------------------------------------------
438 * @see java.lang.Object#toString()
441 @SuppressWarnings("nls")
442 public String
toString() {
443 return "[TmfTrace (" + getName() + ")]";
446 // ------------------------------------------------------------------------
448 // ------------------------------------------------------------------------
451 * The purpose of the index is to keep the information needed to rapidly
452 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
456 @SuppressWarnings({ "unchecked" })
457 protected void indexTrace(boolean waitForCompletion
) {
459 final Job job
= new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
461 protected IStatus
run(IProgressMonitor monitor
) {
462 while (!monitor
.isCanceled()) {
465 } catch (InterruptedException e
) {
466 return Status
.OK_STATUS
;
470 return Status
.OK_STATUS
;
475 fCheckpoints
.clear();
476 ITmfEventRequest
<TmfEvent
> request
= new TmfEventRequest
<TmfEvent
>(TmfEvent
.class, TmfTimeRange
.Eternity
, TmfDataRequest
.ALL_DATA
,
477 fIndexPageSize
, ITmfDataRequest
.ExecutionType
.BACKGROUND
) {
479 TmfTimestamp startTime
= null;
480 TmfTimestamp lastTime
= null;
483 public void handleData(TmfEvent event
) {
484 super.handleData(event
);
486 TmfTimestamp ts
= event
.getTimestamp();
487 if (startTime
== null)
488 startTime
= new TmfTimestamp(ts
);
489 lastTime
= new TmfTimestamp(ts
);
491 if ((getNbRead() % fIndexPageSize
) == 0) {
498 public void handleSuccess() {
503 public void handleCompleted() {
505 super.handleCompleted();
508 private void updateTrace() {
509 int nbRead
= getNbRead();
511 fStartTime
= startTime
;
519 sendRequest((ITmfDataRequest
<T
>) request
);
520 if (waitForCompletion
)
522 request
.waitForCompletion();
523 } catch (InterruptedException e
) {
528 protected void notifyListeners() {
529 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime
, fEndTime
)));