2010-10-26 Francois Chouinard <fchouinard@gmail.com> Contribution for Bug309042
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / trace / TmfTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.trace;
14
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.util.Collections;
18 import java.util.Vector;
19
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;
26
27 /**
28 * <b><u>TmfTrace</u></b>
29 * <p>
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.
34 * <p>
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).
39 * <p>
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.
44 *
45 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
46 */
47 public abstract class TmfTrace<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace, Cloneable {
48
49 // ------------------------------------------------------------------------
50 // Constants
51 // ------------------------------------------------------------------------
52
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;
56
57 // ------------------------------------------------------------------------
58 // Attributes
59 // ------------------------------------------------------------------------
60
61 // The trace path
62 private final String fPath;
63
64 // The cache page size AND checkpoints interval
65 protected int fIndexPageSize;
66
67 // The set of event stream checkpoints (for random access)
68 protected Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
69
70 // The number of events collected
71 protected long fNbEvents = 0;
72
73 // The time span of the event stream
74 private TmfTimestamp fStartTime = TmfTimestamp.BigCrunch;
75 private TmfTimestamp fEndTime = TmfTimestamp.BigBang;
76
77 // ------------------------------------------------------------------------
78 // Constructors
79 // ------------------------------------------------------------------------
80
81 /**
82 * @param path
83 * @throws FileNotFoundException
84 */
85 protected TmfTrace(String name, Class<T> type, String path) throws FileNotFoundException {
86 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE);
87 }
88
89 /**
90 * @param path
91 * @param cacheSize
92 * @throws FileNotFoundException
93 */
94 protected TmfTrace(String name, Class<T> type, String path, int cacheSize) throws FileNotFoundException {
95 super(name, type);
96 int sep = path.lastIndexOf(File.separator);
97 String simpleName = (sep >= 0) ? path.substring(sep + 1) : path;
98 setName(simpleName);
99 fPath = path;
100 fIndexPageSize = (cacheSize > 0) ? cacheSize : DEFAULT_INDEX_PAGE_SIZE;
101 }
102
103 /* (non-Javadoc)
104 * @see java.lang.Object#clone()
105 */
106 @SuppressWarnings("unchecked")
107 @Override
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);
113 return clone;
114 }
115
116 // ------------------------------------------------------------------------
117 // Accessors
118 // ------------------------------------------------------------------------
119
120 /**
121 * @return the trace path
122 */
123 @Override
124 public String getPath() {
125 return fPath;
126 }
127
128 /* (non-Javadoc)
129 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
130 */
131 @Override
132 public long getNbEvents() {
133 return fNbEvents;
134 }
135
136 /**
137 * @return the size of the cache
138 */
139 @Override
140 public int getCacheSize() {
141 return fIndexPageSize;
142 }
143
144 /* (non-Javadoc)
145 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
146 */
147 @Override
148 public TmfTimeRange getTimeRange() {
149 return new TmfTimeRange(fStartTime, fEndTime);
150 }
151
152 /* (non-Javadoc)
153 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
154 */
155 @Override
156 public TmfTimestamp getStartTime() {
157 return fStartTime;
158 }
159
160 /* (non-Javadoc)
161 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
162 */
163 @Override
164 public TmfTimestamp getEndTime() {
165 return fEndTime;
166 }
167
168 @SuppressWarnings("unchecked")
169 public Vector<TmfCheckpoint> getCheckpoints() {
170 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
171 }
172
173 /**
174 * Returns the rank of the first event with the requested timestamp.
175 * If none, returns the index of the next event (if any).
176 *
177 * @param timestamp
178 * @return
179 */
180 @Override
181 public long getRank(TmfTimestamp timestamp) {
182 TmfContext context = seekEvent(timestamp);
183 return context.getRank();
184 }
185
186 // ------------------------------------------------------------------------
187 // Operators
188 // ------------------------------------------------------------------------
189
190 protected void setTimeRange(TmfTimeRange range) {
191 fStartTime = range.getStartTime();
192 fEndTime = range.getEndTime();
193 }
194
195 protected void setStartTime(TmfTimestamp startTime) {
196 fStartTime = startTime;
197 }
198
199 protected void setEndTime(TmfTimestamp endTime) {
200 fEndTime = endTime;
201 }
202
203 // ------------------------------------------------------------------------
204 // TmfProvider
205 // ------------------------------------------------------------------------
206
207 @Override
208 public ITmfContext armRequest(ITmfDataRequest<T> request) {
209 if (request instanceof ITmfEventRequest<?>) {
210 return seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
211 }
212 return seekEvent(request.getIndex());
213 }
214
215 /**
216 * Return the next piece of data based on the context supplied. The context
217 * would typically be updated for the subsequent read.
218 *
219 * @param context
220 * @return
221 */
222 @SuppressWarnings("unchecked")
223 @Override
224 public T getNext(ITmfContext context) {
225 if (context instanceof TmfContext) {
226 return (T) getNextEvent((TmfContext) context);
227 }
228 return null;
229 }
230
231 // ------------------------------------------------------------------------
232 // ITmfTrace
233 // ------------------------------------------------------------------------
234
235 /* (non-Javadoc)
236 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
237 */
238 @Override
239 public TmfContext seekEvent(TmfTimestamp timestamp) {
240
241 if (timestamp == null) {
242 timestamp = TmfTimestamp.BigBang;
243 }
244
245 // First, find the right checkpoint
246 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
247
248 // In the very likely case that the checkpoint was not found, bsearch
249 // returns its negated would-be location (not an offset...). From that
250 // index, we can then position the stream and get the event.
251 if (index < 0) {
252 index = Math.max(0, -(index + 2));
253 }
254
255 // Position the stream at the checkpoint
256 ITmfLocation<?> location;
257 synchronized (fCheckpoints) {
258 if (fCheckpoints.size() > 0) {
259 if (index >= fCheckpoints.size()) {
260 index = fCheckpoints.size() - 1;
261 }
262 location = fCheckpoints.elementAt(index).getLocation();
263 }
264 else {
265 location = null;
266 }
267 }
268 TmfContext context = seekLocation(location);
269 context.setRank(index * fIndexPageSize);
270
271 // And locate the event
272 TmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype...
273 TmfEvent event = getNextEvent(nextEventContext);
274 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
275 context.setLocation(nextEventContext.getLocation().clone());
276 context.updateRank(1);
277 event = getNextEvent(nextEventContext);
278 }
279
280 return context;
281 }
282
283 /* (non-Javadoc)
284 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
285 */
286 @Override
287 public TmfContext seekEvent(long rank) {
288
289 // Position the stream at the previous checkpoint
290 int index = (int) rank / fIndexPageSize;
291 ITmfLocation<?> location;
292 synchronized (fCheckpoints) {
293 if (fCheckpoints.size() == 0) {
294 location = null;
295 }
296 else {
297 if (index >= fCheckpoints.size()) {
298 index = fCheckpoints.size() - 1;
299 }
300 location = fCheckpoints.elementAt(index).getLocation();
301 }
302 }
303
304 TmfContext context = seekLocation(location);
305 long pos = index * fIndexPageSize;
306 context.setRank(pos);
307
308 if (pos < rank) {
309 TmfEvent event = getNextEvent(context);
310 while (event != null && ++pos < rank) {
311 event = getNextEvent(context);
312 }
313 }
314
315 return context;
316 }
317
318 /* (non-Javadoc)
319 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.trace.ITmfTrace.TraceContext)
320 */
321 @Override
322 public synchronized TmfEvent getNextEvent(TmfContext context) {
323 // parseEvent() does not update the context
324 TmfEvent event = parseEvent(context);
325 if (event != null) {
326 updateIndex(context, context.getRank(), event.getTimestamp());
327 context.setLocation(getCurrentLocation());
328 context.updateRank(1);
329 processEvent(event);
330 }
331 return event;
332 }
333
334 protected synchronized void updateIndex(ITmfContext context, long rank, TmfTimestamp timestamp) {
335 if (fStartTime.compareTo(timestamp, false) > 0) fStartTime = timestamp;
336 if (fEndTime.compareTo(timestamp, false) < 0) fEndTime = timestamp;
337 if (context.isValidRank()) {
338 if (fNbEvents <= rank)
339 fNbEvents = rank + 1;
340 // Build the index as we go along
341 if ((rank % fIndexPageSize) == 0) {
342 // Determine the table position
343 long position = rank / fIndexPageSize;
344 // Add new entry at proper location (if empty)
345 if (fCheckpoints.size() == position) {
346 ITmfLocation<?> location = context.getLocation().clone();
347 fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location));
348 // System.out.println(getName() + "[" + (fCheckpoints.size() - 1) + "] " + timestamp + ", " + location.toString());
349 }
350 }
351 }
352 }
353
354 /**
355 * Hook for "special" processing by the concrete class
356 * (called by getNextEvent())
357 *
358 * @param event
359 */
360 protected void processEvent(TmfEvent event) {
361 // Do nothing by default
362 }
363
364 /**
365 * To be implemented by the concrete class
366 */
367 @Override
368 public abstract TmfContext seekLocation(ITmfLocation<?> location);
369 public abstract ITmfLocation<?> getCurrentLocation();
370 @Override
371 public abstract TmfEvent parseEvent(TmfContext context);
372
373 // ------------------------------------------------------------------------
374 // toString
375 // ------------------------------------------------------------------------
376
377 /* (non-Javadoc)
378 * @see java.lang.Object#toString()
379 */
380 @Override
381 public String toString() {
382 return "[TmfTrace (" + getName() + ")]";
383 }
384
385 // ------------------------------------------------------------------------
386 // Indexing
387 // ------------------------------------------------------------------------
388
389 // /*
390 // * The purpose of the index is to keep the information needed to rapidly
391 // * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
392 // * event).
393 // */
394 //
395 // @SuppressWarnings({ "unchecked", "unused" })
396 // private void indexTrace(boolean waitForCompletion) {
397 //
398 // fCheckpoints.clear();
399 //
400 // ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, TmfDataRequest.ALL_DATA, 1, ITmfDataRequest.ExecutionType.BACKGROUND) {
401 //
402 // TmfTimestamp startTime = null;
403 // TmfTimestamp lastTime = null;
404 //
405 // @Override
406 // public void handleData() {
407 // TmfEvent[] events = getData();
408 // if (events.length > 0) {
409 // TmfTimestamp ts = events[0].getTimestamp();
410 // if (startTime == null) {
411 // startTime = new TmfTimestamp(ts);
412 // fStartTime = startTime;
413 // }
414 // lastTime = new TmfTimestamp(ts);
415 //
416 // if ((fNbRead % DEFAULT_INDEX_PAGE_SIZE) == 0) {
417 // updateTraceData();
418 // }
419 // }
420 // }
421 //
422 // @Override
423 // public void handleSuccess() {
424 // updateTraceData();
425 // }
426 //
427 // private void updateTraceData() {
428 // if (fNbRead != 0) {
429 // fEndTime = new TmfTimestamp(lastTime);
430 // fNbEvents = fNbRead;
431 // notifyListeners();
432 // }
433 // }
434 // };
435 //
436 // sendRequest((ITmfDataRequest<T>) request);
437 // if (waitForCompletion)
438 // try {
439 // request.waitForCompletion();
440 // } catch (InterruptedException e) {
441 // e.printStackTrace();
442 // }
443 // }
444
445 // protected void notifyListeners() {
446 // broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
447 // }
448
449 // ------------------------------------------------------------------------
450 // TmfDataProvider
451 // ------------------------------------------------------------------------
452
453 // @Override
454 // protected void queueBackgroundRequest(final ITmfDataRequest<T> request, final int blockSize, final boolean adjust) {
455 // super.queueBackgroundRequest(request, fIndexPageSize, true);
456 // }
457
458 }
This page took 0.040067 seconds and 5 git commands to generate.