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
.linuxtools
.tmf
.component
.TmfEventProvider
;
21 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
22 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
23 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
24 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfDataRequest
;
25 import org
.eclipse
.linuxtools
.tmf
.request
.ITmfEventRequest
;
28 * <b><u>TmfTrace</u></b>
30 * Abstract implementation of ITmfTrace. It should be sufficient to extend this
31 * class and provide implementation for <code>getCurrentLocation()</code> and
32 * <code>seekLocation()</code>, as well as a proper parser, to have a working
33 * concrete implementation.
35 * Note: The notion of event rank is still under heavy discussion. Although
36 * used by the Events View and probably useful in the general case, there
37 * is no easy way to implement it for LTTng (actually a strong case is being
38 * made that this is useless).
40 * That it is not supported by LTTng does by no mean indicate that it is not
41 * useful for (just about) every other tracing tool. Therefore, this class
42 * provides a minimal (and partial) implementation of rank. However, the current
43 * implementation should not be relied on in the general case.
45 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
47 public abstract class TmfTrace
<T
extends TmfEvent
> extends TmfEventProvider
<T
> implements ITmfTrace
, Cloneable
{
49 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
53 // The default number of events to cache
54 // TODO: Make the DEFAULT_CACHE_SIZE a preference
55 public static final int DEFAULT_INDEX_PAGE_SIZE
= 1000;
57 // ------------------------------------------------------------------------
59 // ------------------------------------------------------------------------
62 private final String fPath
;
64 // The cache page size AND checkpoints interval
65 protected int fIndexPageSize
;
67 // The set of event stream checkpoints (for random access)
68 protected Vector
<TmfCheckpoint
> fCheckpoints
= new Vector
<TmfCheckpoint
>();
70 // The number of events collected
71 protected long fNbEvents
= 0;
73 // The time span of the event stream
74 private TmfTimestamp fStartTime
= TmfTimestamp
.BigCrunch
;
75 private TmfTimestamp fEndTime
= TmfTimestamp
.BigBang
;
77 // ------------------------------------------------------------------------
79 // ------------------------------------------------------------------------
83 * @throws FileNotFoundException
85 protected TmfTrace(String name
, Class
<T
> type
, String path
) throws FileNotFoundException
{
86 this(name
, type
, path
, DEFAULT_INDEX_PAGE_SIZE
);
92 * @throws FileNotFoundException
94 protected TmfTrace(String name
, Class
<T
> type
, String path
, int cacheSize
) throws FileNotFoundException
{
96 int sep
= path
.lastIndexOf(File
.separator
);
97 String simpleName
= (sep
>= 0) ? path
.substring(sep
+ 1) : path
;
100 fIndexPageSize
= (cacheSize
> 0) ? cacheSize
: DEFAULT_INDEX_PAGE_SIZE
;
104 * @see java.lang.Object#clone()
106 @SuppressWarnings("unchecked")
108 public TmfTrace
<T
> clone() throws CloneNotSupportedException
{
109 TmfTrace
<T
> clone
= (TmfTrace
<T
>) super.clone();
110 clone
.fCheckpoints
= (Vector
<TmfCheckpoint
>) fCheckpoints
;
111 clone
.fStartTime
= new TmfTimestamp(fStartTime
);
112 clone
.fEndTime
= new TmfTimestamp(fEndTime
);
116 // ------------------------------------------------------------------------
118 // ------------------------------------------------------------------------
121 * @return the trace path
123 public String
getPath() {
128 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
130 public long getNbEvents() {
135 * @return the size of the cache
137 public int getCacheSize() {
138 return fIndexPageSize
;
142 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
144 public TmfTimeRange
getTimeRange() {
145 return new TmfTimeRange(fStartTime
, fEndTime
);
149 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
151 public TmfTimestamp
getStartTime() {
156 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
158 public TmfTimestamp
getEndTime() {
162 @SuppressWarnings("unchecked")
163 public Vector
<TmfCheckpoint
> getCheckpoints() {
164 return (Vector
<TmfCheckpoint
>) fCheckpoints
.clone();
168 * Returns the rank of the first event with the requested timestamp.
169 * If none, returns the index of the next event (if any).
174 public long getRank(TmfTimestamp timestamp
) {
175 TmfContext context
= seekEvent(timestamp
);
176 return context
.getRank();
179 // ------------------------------------------------------------------------
181 // ------------------------------------------------------------------------
183 protected void setTimeRange(TmfTimeRange range
) {
184 fStartTime
= range
.getStartTime();
185 fEndTime
= range
.getEndTime();
188 protected void setStartTime(TmfTimestamp startTime
) {
189 fStartTime
= startTime
;
192 protected void setEndTime(TmfTimestamp endTime
) {
196 // ------------------------------------------------------------------------
198 // ------------------------------------------------------------------------
201 public ITmfContext
armRequest(ITmfDataRequest
<T
> request
) {
202 if (request
instanceof ITmfEventRequest
<?
>) {
203 return seekEvent(((ITmfEventRequest
<T
>) request
).getRange().getStartTime());
205 return seekEvent(request
.getIndex());
209 * Return the next piece of data based on the context supplied. The context
210 * would typically be updated for the subsequent read.
215 @SuppressWarnings("unchecked")
217 public T
getNext(ITmfContext context
) {
218 if (context
instanceof TmfContext
) {
219 return (T
) getNextEvent((TmfContext
) context
);
224 // ------------------------------------------------------------------------
226 // ------------------------------------------------------------------------
229 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
231 public TmfContext
seekEvent(TmfTimestamp timestamp
) {
233 if (timestamp
== null) {
234 timestamp
= TmfTimestamp
.BigBang
;
237 // First, find the right checkpoint
238 int index
= Collections
.binarySearch(fCheckpoints
, new TmfCheckpoint(timestamp
, null));
240 // In the very likely case that the checkpoint was not found, bsearch
241 // returns its negated would-be location (not an offset...). From that
242 // index, we can then position the stream and get the event.
244 index
= Math
.max(0, -(index
+ 2));
247 // Position the stream at the checkpoint
248 ITmfLocation
<?
> location
;
249 synchronized (fCheckpoints
) {
250 if (fCheckpoints
.size() > 0) {
251 if (index
>= fCheckpoints
.size()) {
252 index
= fCheckpoints
.size() - 1;
254 location
= fCheckpoints
.elementAt(index
).getLocation();
260 TmfContext context
= seekLocation(location
);
261 context
.setRank(index
* fIndexPageSize
);
263 // And locate the event
264 TmfContext nextEventContext
= context
.clone(); // Must use clone() to get the right subtype...
265 TmfEvent event
= getNextEvent(nextEventContext
);
266 while (event
!= null && event
.getTimestamp().compareTo(timestamp
, false) < 0) {
267 context
.setLocation(nextEventContext
.getLocation().clone());
268 context
.updateRank(1);
269 event
= getNextEvent(nextEventContext
);
276 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
278 public TmfContext
seekEvent(long rank
) {
280 // Position the stream at the previous checkpoint
281 int index
= (int) rank
/ fIndexPageSize
;
282 ITmfLocation
<?
> location
;
283 synchronized (fCheckpoints
) {
284 if (fCheckpoints
.size() == 0) {
288 if (index
>= fCheckpoints
.size()) {
289 index
= fCheckpoints
.size() - 1;
291 location
= fCheckpoints
.elementAt(index
).getLocation();
295 TmfContext context
= seekLocation(location
);
296 long pos
= index
* fIndexPageSize
;
297 context
.setRank(pos
);
300 TmfEvent event
= getNextEvent(context
);
301 while (event
!= null && ++pos
< rank
) {
302 event
= getNextEvent(context
);
310 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
312 public synchronized TmfEvent
getNextEvent(TmfContext context
) {
313 // parseEvent() does not update the context
314 TmfEvent event
= parseEvent(context
);
316 updateIndex(context
, context
.getRank(), event
.getTimestamp());
317 context
.setLocation(getCurrentLocation());
318 context
.updateRank(1);
324 protected synchronized void updateIndex(ITmfContext context
, long rank
, TmfTimestamp timestamp
) {
325 if (fStartTime
.compareTo(timestamp
, false) > 0) fStartTime
= timestamp
;
326 if (fEndTime
.compareTo(timestamp
, false) < 0) fEndTime
= timestamp
;
327 if (context
.isValidRank()) {
328 if (fNbEvents
<= rank
)
329 fNbEvents
= rank
+ 1;
330 // Build the index as we go along
331 if ((rank
% fIndexPageSize
) == 0) {
332 // Determine the table position
333 long position
= rank
/ fIndexPageSize
;
334 // Add new entry at proper location (if empty)
335 if (fCheckpoints
.size() == position
) {
336 ITmfLocation
<?
> location
= context
.getLocation().clone();
337 fCheckpoints
.add(new TmfCheckpoint(timestamp
.clone(), location
));
338 // System.out.println(getName() + "[" + (fCheckpoints.size() - 1) + "] " + timestamp + ", " + location.toString());
345 * Hook for "special" processing by the concrete class
346 * (called by getNextEvent())
350 protected void processEvent(TmfEvent event
) {
351 // Do nothing by default
355 * To be implemented by the concrete class
357 public abstract TmfContext
seekLocation(ITmfLocation
<?
> location
);
358 public abstract ITmfLocation
<?
> getCurrentLocation();
359 public abstract TmfEvent
parseEvent(TmfContext context
);
361 // ------------------------------------------------------------------------
363 // ------------------------------------------------------------------------
366 * @see java.lang.Object#toString()
369 public String
toString() {
370 return "[TmfTrace (" + getName() + ")]";
373 // ------------------------------------------------------------------------
375 // ------------------------------------------------------------------------
378 // * The purpose of the index is to keep the information needed to rapidly
379 // * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
383 // @SuppressWarnings({ "unchecked", "unused" })
384 // private void indexTrace(boolean waitForCompletion) {
386 // fCheckpoints.clear();
388 // ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, TmfDataRequest.ALL_DATA, 1, ITmfDataRequest.ExecutionType.BACKGROUND) {
390 // TmfTimestamp startTime = null;
391 // TmfTimestamp lastTime = null;
394 // public void handleData() {
395 // TmfEvent[] events = getData();
396 // if (events.length > 0) {
397 // TmfTimestamp ts = events[0].getTimestamp();
398 // if (startTime == null) {
399 // startTime = new TmfTimestamp(ts);
400 // fStartTime = startTime;
402 // lastTime = new TmfTimestamp(ts);
404 // if ((fNbRead % DEFAULT_INDEX_PAGE_SIZE) == 0) {
405 // updateTraceData();
411 // public void handleSuccess() {
412 // updateTraceData();
415 // private void updateTraceData() {
416 // if (fNbRead != 0) {
417 // fEndTime = new TmfTimestamp(lastTime);
418 // fNbEvents = fNbRead;
419 // notifyListeners();
424 // sendRequest((ITmfDataRequest<T>) request);
425 // if (waitForCompletion)
427 // request.waitForCompletion();
428 // } catch (InterruptedException e) {
429 // e.printStackTrace();
433 // protected void notifyListeners() {
434 // broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
437 // ------------------------------------------------------------------------
439 // ------------------------------------------------------------------------
442 // protected void queueBackgroundRequest(final ITmfDataRequest<T> request, final int blockSize, final boolean adjust) {
443 // super.queueBackgroundRequest(request, fIndexPageSize, true);