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
.core
.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
.resources
.IResource
;
22 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
23 import org
.eclipse
.core
.runtime
.IStatus
;
24 import org
.eclipse
.core
.runtime
.Path
;
25 import org
.eclipse
.core
.runtime
.Status
;
26 import org
.eclipse
.core
.runtime
.jobs
.Job
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.component
.TmfEventProvider
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfDataRequest
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfEventRequest
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
39 * <b><u>TmfTrace</u></b>
41 * Abstract implementation of ITmfTrace. It should be sufficient to extend this class and provide implementation for
42 * <code>getCurrentLocation()</code> and <code>seekLocation()</code>, as well as a proper parser, to have a working
43 * concrete implementation.
45 * Note: The notion of event rank is still under heavy discussion. Although used by the Events View and probably useful
46 * in the general case, there is no easy way to implement it for LTTng (actually a strong case is being made that this
49 * That it is not supported by LTTng does by no mean indicate that it is not useful for (just about) every other tracing
50 * tool. Therefore, this class provides a minimal (and partial) implementation of rank. However, the current
51 * implementation should not be relied on in the general case.
53 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
55 public abstract class TmfTrace
<T
extends ITmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
<T
>, Cloneable
{
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
61 // The default number of events to cache
62 // TODO: Make the DEFAULT_CACHE_SIZE a preference
63 public static final int DEFAULT_INDEX_PAGE_SIZE
= 50000;
65 // ------------------------------------------------------------------------
67 // ------------------------------------------------------------------------
73 private String fTraceName
;
75 // The cache page size AND checkpoints interval
76 protected int fIndexPageSize
= DEFAULT_INDEX_PAGE_SIZE
;
78 // The set of event stream checkpoints (for random access)
79 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
81 // The number of events collected
82 protected long fNbEvents
= 0;
84 // The time span of the event stream
85 private ITmfTimestamp fStartTime
= TmfTimestamp
.BIG_CRUNCH
;
86 private ITmfTimestamp fEndTime
= TmfTimestamp
.BIG_BANG
;
88 // The properties resource
89 private IResource fResource
;
91 // ------------------------------------------------------------------------
93 // ------------------------------------------------------------------------
100 public void initTrace(String name
, String path
, Class
<T
> eventType
) throws FileNotFoundException
{
105 if (fTraceName
== null) {
106 fTraceName
= ""; //$NON-NLS-1$
108 int sep
= path
.lastIndexOf(Path
.SEPARATOR
);
109 fTraceName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
112 super.init(fTraceName
, eventType
);
116 public boolean validate(IProject project
, String path
) {
117 File file
= new File(path
);
118 return file
.exists();
123 * @throws FileNotFoundException
125 protected TmfTrace(String name
, Class
<T
> type
, String path
) throws FileNotFoundException
{
126 this(name
, type
, path
, DEFAULT_INDEX_PAGE_SIZE
, true);
132 * @throws FileNotFoundException
134 protected TmfTrace(String name
, Class
<T
> type
, String path
, int cacheSize
) throws FileNotFoundException
{
135 this(name
, type
, path
, cacheSize
, true);
141 * @throws FileNotFoundException
143 protected TmfTrace(String name
, Class
<T
> type
, String path
, boolean indexTrace
) throws FileNotFoundException
{
144 this(name
, type
, path
, DEFAULT_INDEX_PAGE_SIZE
, indexTrace
);
151 * @throws FileNotFoundException
153 protected TmfTrace(String name
, Class
<T
> type
, String path
, int indexPageSize
, boolean indexTrace
) throws FileNotFoundException
{
155 initTrace(name
, path
, type
);
156 fIndexPageSize
= (indexPageSize
>0) ? indexPageSize
: DEFAULT_INDEX_PAGE_SIZE
;
161 @SuppressWarnings("unchecked")
163 public TmfTrace
<T
> clone() throws CloneNotSupportedException
{
164 TmfTrace
<T
> clone
= (TmfTrace
<T
>) super.clone();
165 clone
.fCheckpoints
= fCheckpoints
;
166 clone
.fStartTime
= fStartTime
.clone();
167 clone
.fEndTime
= fEndTime
.clone();
171 // ------------------------------------------------------------------------
173 // ------------------------------------------------------------------------
176 * @return the trace path
179 public String
getPath() {
184 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
187 public synchronized long getNbEvents() {
192 * @return the size of the cache
195 public int getIndexPageSize() {
196 return fIndexPageSize
;
200 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
203 public TmfTimeRange
getTimeRange() {
204 return new TmfTimeRange(fStartTime
, fEndTime
);
208 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
211 public ITmfTimestamp
getStartTime() {
216 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
219 public ITmfTimestamp
getEndTime() {
224 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
227 public long getStreamingInterval() {
231 @SuppressWarnings("unchecked")
232 public Vector
<TmfCheckpoint
> getCheckpoints() {
233 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
237 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
240 * @param timestamp the requested event timestamp
241 * @return the corresponding event rank
244 public long getRank(ITmfTimestamp timestamp
) {
245 TmfContext context
= seekEvent(timestamp
);
246 return context
.getRank();
249 // ------------------------------------------------------------------------
251 // ------------------------------------------------------------------------
253 protected void setTimeRange(TmfTimeRange range
) {
254 fStartTime
= range
.getStartTime();
255 fEndTime
= range
.getEndTime();
258 protected void setStartTime(ITmfTimestamp startTime
) {
259 fStartTime
= startTime
;
262 protected void setEndTime(ITmfTimestamp endTime
) {
266 // ------------------------------------------------------------------------
268 // ------------------------------------------------------------------------
271 public ITmfContext
armRequest(ITmfDataRequest
<T
> request
) {
272 if (request
instanceof ITmfEventRequest
<?
>
273 && !TmfTimestamp
.BIG_BANG
.equals(((ITmfEventRequest
<T
>) request
).getRange().getStartTime()) && request
.getIndex() == 0) {
274 ITmfContext context
= seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
275 ((ITmfEventRequest
<T
>) request
).setStartIndex((int) context
.getRank());
279 return seekEvent(request
.getIndex());
283 * Return the next piece of data based on the context supplied. The context would typically be updated for the
287 * @return the event referred to by context
289 @SuppressWarnings("unchecked")
291 public T
getNext(ITmfContext context
) {
292 if (context
instanceof TmfContext
) {
293 return (T
) getNextEvent((TmfContext
) context
);
298 // ------------------------------------------------------------------------
300 // ------------------------------------------------------------------------
303 public abstract TmfContext
seekLocation(ITmfLocation
<?
> location
);
306 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
309 public TmfContext
seekEvent(ITmfTimestamp ts
) {
311 ITmfTimestamp timestamp
= ts
;
312 if (timestamp
== null) {
313 timestamp
= TmfTimestamp
.BIG_BANG
;
316 // First, find the right checkpoint
317 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
319 // In the very likely case that the checkpoint was not found, bsearch
320 // returns its negated would-be location (not an offset...). From that
321 // index, we can then position the stream and get the event.
323 index
= Math
.max(0, -(index
+ 2));
326 // Position the stream at the checkpoint
327 ITmfLocation
<?
> location
;
328 synchronized (fCheckpoints
) {
329 if (!fCheckpoints
.isEmpty()) {
330 if (index
>= fCheckpoints
.size()) {
331 index
= fCheckpoints
.size() - 1;
333 location
= fCheckpoints
.elementAt(index
).getLocation();
338 TmfContext context
= seekLocation(location
);
339 context
.setRank(index
* fIndexPageSize
);
341 // And locate the event
342 TmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
343 ITmfEvent event
= getNextEvent(nextEventContext
);
344 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
345 context
.setLocation(nextEventContext
.getLocation().clone());
346 context
.updateRank(1);
347 event
= getNextEvent(nextEventContext
);
354 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
357 public TmfContext
seekEvent(long rank
) {
359 // Position the stream at the previous checkpoint
360 int index
= (int) rank
/ fIndexPageSize
;
361 ITmfLocation
<?
> location
;
362 synchronized (fCheckpoints
) {
363 if (fCheckpoints
.isEmpty()) {
366 if (index
>= fCheckpoints
.size()) {
367 index
= fCheckpoints
.size() - 1;
369 location
= fCheckpoints
.elementAt(index
).getLocation();
373 TmfContext context
= seekLocation(location
);
374 long pos
= index
* fIndexPageSize
;
375 context
.setRank(pos
);
378 ITmfEvent event
= getNextEvent(context
);
379 while (event
!= null && ++pos
< rank
) {
380 event
= getNextEvent(context
);
390 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
391 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
394 public synchronized ITmfEvent
getNextEvent(ITmfContext context
) {
395 // parseEvent() does not update the context
396 ITmfEvent event
= parseEvent(context
);
398 updateIndex(context
, context
.getRank(), event
.getTimestamp());
399 context
.setLocation(getCurrentLocation());
400 context
.updateRank(1);
406 protected synchronized void updateIndex(ITmfContext context
, long rank
, ITmfTimestamp timestamp
) {
407 if (fStartTime
.compareTo(timestamp
, false) > 0)
408 fStartTime
= timestamp
;
409 if (fEndTime
.compareTo(timestamp
, false) < 0)
410 fEndTime
= timestamp
;
411 if (context
.isValidRank()) {
412 if (fNbEvents
<= rank
)
413 fNbEvents
= rank
+ 1;
414 // Build the index as we go along
415 if ((rank
% fIndexPageSize
) == 0) {
416 // Determine the table position
417 long position
= rank
/ fIndexPageSize
;
418 // Add new entry at proper location (if empty)
419 if (fCheckpoints
.size() == position
) {
420 ITmfLocation
<?
> location
= context
.getLocation().clone();
421 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
422 // System.out.println(getName() + "[" + (fCheckpoints.size()
423 // - 1) + "] " + timestamp + ", " + location.toString());
430 * Hook for special processing by the concrete class (called by getNextEvent())
434 protected void processEvent(ITmfEvent event
) {
435 // Do nothing by default
438 // ------------------------------------------------------------------------
440 // ------------------------------------------------------------------------
443 * @see java.lang.Object#toString()
446 @SuppressWarnings("nls")
447 public String
toString() {
448 return "[TmfTrace (" + getName() + ")]";
451 // ------------------------------------------------------------------------
453 // ------------------------------------------------------------------------
456 * The purpose of the index is to keep the information needed to rapidly
457 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
462 @SuppressWarnings({ "unchecked" })
463 public void indexTrace(boolean waitForCompletion
) {
465 final Job job
= new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
467 protected IStatus
run(IProgressMonitor monitor
) {
468 while (!monitor
.isCanceled()) {
471 } catch (InterruptedException e
) {
472 return Status
.OK_STATUS
;
476 return Status
.OK_STATUS
;
481 fCheckpoints
.clear();
482 ITmfEventRequest
<ITmfEvent
> request
= new TmfEventRequest
<ITmfEvent
>(ITmfEvent
.class, TmfTimeRange
.ETERNITY
, TmfDataRequest
.ALL_DATA
,
483 fIndexPageSize
, ITmfDataRequest
.ExecutionType
.BACKGROUND
) {
485 ITmfTimestamp startTime
= null;
486 ITmfTimestamp lastTime
= null;
489 public void handleData(ITmfEvent event
) {
490 super.handleData(event
);
492 ITmfTimestamp ts
= event
.getTimestamp();
493 if (startTime
== null)
494 startTime
= ts
.clone();
495 lastTime
= ts
.clone();
497 if ((getNbRead() % fIndexPageSize
) == 0) {
504 public void handleSuccess() {
509 public void handleCompleted() {
511 super.handleCompleted();
514 private synchronized void updateTrace() {
515 int nbRead
= getNbRead();
517 fStartTime
= startTime
;
525 sendRequest((ITmfDataRequest
<T
>) request
);
526 if (waitForCompletion
)
528 request
.waitForCompletion();
529 } catch (InterruptedException e
) {
530 // e.printStackTrace();
534 protected void notifyListeners() {
535 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime
, fEndTime
)));
540 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#setResource(org.eclipse.core.resources.IResource)
543 public void setResource(IResource resource
) {
544 fResource
= resource
;
549 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
552 public IResource
getResource() {