Integrate the TmfEvent+ITmfTimestamp API
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / 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.core.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.core.resources.IProject;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.Path;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.jobs.Job;
26 import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider;
27 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
28 import org.eclipse.linuxtools.tmf.core.event.TmfEvent;
29 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
30 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
31 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
32 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
33 import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
34 import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
35 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
36
37 /**
38 * <b><u>TmfTrace</u></b>
39 * <p>
40 * Abstract implementation of ITmfTrace. It should be sufficient to extend this class and provide implementation for
41 * <code>getCurrentLocation()</code> and <code>seekLocation()</code>, as well as a proper parser, to have a working
42 * concrete implementation.
43 * <p>
44 * Note: The notion of event rank is still under heavy discussion. Although used by the Events View and probably useful
45 * in the general case, there is no easy way to implement it for LTTng (actually a strong case is being made that this
46 * is useless).
47 * <p>
48 * That it is not supported by LTTng does by no mean indicate that it is not useful for (just about) every other tracing
49 * tool. Therefore, this class provides a minimal (and partial) implementation of rank. However, the current
50 * implementation should not be relied on in the general case.
51 *
52 * TODO: Add support for live streaming (notifications, incremental indexing, ...)
53 */
54 public abstract class TmfTrace<T extends TmfEvent> extends TmfEventProvider<T> implements ITmfTrace<T>, Cloneable {
55
56 // ------------------------------------------------------------------------
57 // Constants
58 // ------------------------------------------------------------------------
59
60 // The default number of events to cache
61 // TODO: Make the DEFAULT_CACHE_SIZE a preference
62 public static final int DEFAULT_INDEX_PAGE_SIZE = 50000;
63
64 // ------------------------------------------------------------------------
65 // Attributes
66 // ------------------------------------------------------------------------
67
68 // The trace path
69 private String fPath;
70
71 // The trace name
72 private String fTraceName;
73
74 // The cache page size AND checkpoints interval
75 protected int fIndexPageSize = DEFAULT_INDEX_PAGE_SIZE;
76
77 // The set of event stream checkpoints (for random access)
78 protected Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
79
80 // The number of events collected
81 protected long fNbEvents = 0;
82
83 // The time span of the event stream
84 private ITmfTimestamp fStartTime = TmfTimestamp.BigCrunch;
85 private ITmfTimestamp fEndTime = TmfTimestamp.BigBang;
86
87 // ------------------------------------------------------------------------
88 // Constructors
89 // ------------------------------------------------------------------------
90
91 public TmfTrace() {
92 super();
93 }
94
95 @Override
96 public void initTrace(String path, Class<T> eventType) throws FileNotFoundException {
97 initTmfTrace(path, eventType, DEFAULT_INDEX_PAGE_SIZE, false, null);
98 }
99
100 @Override
101 public void initTrace(String path, Class<T> eventType, int cacheSize) throws FileNotFoundException {
102 initTmfTrace(path, eventType, cacheSize, false, null);
103 }
104
105 @Override
106 public void initTrace(String path, Class<T> eventType, boolean indexTrace) throws FileNotFoundException {
107 initTmfTrace(path, eventType, DEFAULT_INDEX_PAGE_SIZE, indexTrace, null);
108 }
109
110 @Override
111 public void initTrace(String path, Class<T> eventType, int cacheSize, boolean indexTrace) throws FileNotFoundException {
112 initTmfTrace(path, eventType, cacheSize, indexTrace, null);
113 }
114
115 @Override
116 public void initTrace(String path, Class<T> eventType, int cacheSize, boolean indexTrace, String name) throws FileNotFoundException {
117 initTmfTrace(path, eventType, cacheSize, indexTrace, name);
118 }
119
120 private void initTmfTrace(String path, Class<T> eventType, int cacheSize, boolean indexTrace, String name) throws FileNotFoundException {
121 fPath = path;
122 if (name != null) {
123 fTraceName = name;
124 }
125 if (fTraceName == null) {
126 fTraceName = ""; //$NON-NLS-1$
127 if (path != null) {
128 int sep = path.lastIndexOf(Path.SEPARATOR);
129 fTraceName = (sep >= 0) ? path.substring(sep + 1) : path;
130 }
131 }
132 super.init(fTraceName, eventType);
133 fIndexPageSize = (cacheSize > 0) ? cacheSize : DEFAULT_INDEX_PAGE_SIZE;
134 if (indexTrace)
135 indexTrace(false);
136 }
137
138 @Override
139 public boolean validate(IProject project, String path) {
140 File file = new File(path);
141 return file.exists();
142 }
143
144 /**
145 * @param path
146 * @throws FileNotFoundException
147 */
148 protected TmfTrace(String name, Class<T> type, String path) throws FileNotFoundException {
149 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE, true);
150 }
151
152 /**
153 * @param path
154 * @param cacheSize
155 * @throws FileNotFoundException
156 */
157 protected TmfTrace(String name, Class<T> type, String path, int cacheSize) throws FileNotFoundException {
158 this(name, type, path, cacheSize, true);
159 }
160
161 /**
162 * @param path
163 * @param indexTrace
164 * @throws FileNotFoundException
165 */
166 protected TmfTrace(String name, Class<T> type, String path, boolean indexTrace) throws FileNotFoundException {
167 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE, indexTrace);
168 }
169
170 /**
171 * @param path
172 * @param cacheSize
173 * @param indexTrace
174 * @throws FileNotFoundException
175 */
176 protected TmfTrace(String name, Class<T> type, String path, int cacheSize, boolean indexTrace) throws FileNotFoundException {
177 super();
178 fTraceName = name;
179 initTrace(path, type, cacheSize, indexTrace);
180 }
181
182 @SuppressWarnings("unchecked")
183 @Override
184 public TmfTrace<T> clone() throws CloneNotSupportedException {
185 TmfTrace<T> clone = (TmfTrace<T>) super.clone();
186 clone.fCheckpoints = fCheckpoints;
187 clone.fStartTime = fStartTime.clone();
188 clone.fEndTime = fEndTime.clone();
189 return clone;
190 }
191
192 // ------------------------------------------------------------------------
193 // Accessors
194 // ------------------------------------------------------------------------
195
196 /**
197 * @return the trace path
198 */
199 @Override
200 public String getPath() {
201 return fPath;
202 }
203
204 /* (non-Javadoc)
205 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
206 */
207 @Override
208 public long getNbEvents() {
209 return fNbEvents;
210 }
211
212 /**
213 * @return the size of the cache
214 */
215 @Override
216 public int getCacheSize() {
217 return fIndexPageSize;
218 }
219
220 /* (non-Javadoc)
221 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
222 */
223 @Override
224 public TmfTimeRange getTimeRange() {
225 return new TmfTimeRange(fStartTime, fEndTime);
226 }
227
228 /* (non-Javadoc)
229 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
230 */
231 @Override
232 public ITmfTimestamp getStartTime() {
233 return fStartTime;
234 }
235
236 /* (non-Javadoc)
237 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
238 */
239 @Override
240 public ITmfTimestamp getEndTime() {
241 return fEndTime;
242 }
243
244 @SuppressWarnings("unchecked")
245 public Vector<TmfCheckpoint> getCheckpoints() {
246 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
247 }
248
249 /**
250 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
251 * (if any).
252 *
253 * @param timestamp
254 * @return
255 */
256 @Override
257 public long getRank(ITmfTimestamp timestamp) {
258 TmfContext context = seekEvent(timestamp);
259 return context.getRank();
260 }
261
262 // ------------------------------------------------------------------------
263 // Operators
264 // ------------------------------------------------------------------------
265
266 protected void setTimeRange(TmfTimeRange range) {
267 fStartTime = range.getStartTime();
268 fEndTime = range.getEndTime();
269 }
270
271 protected void setStartTime(TmfTimestamp startTime) {
272 fStartTime = startTime;
273 }
274
275 protected void setEndTime(TmfTimestamp endTime) {
276 fEndTime = endTime;
277 }
278
279 // ------------------------------------------------------------------------
280 // TmfProvider
281 // ------------------------------------------------------------------------
282
283 @Override
284 public ITmfContext armRequest(ITmfDataRequest<T> request) {
285 if (request instanceof ITmfEventRequest<?>
286 && !TmfTimestamp.BigBang.equals(((ITmfEventRequest<T>) request).getRange().getStartTime()) && request.getIndex() == 0) {
287 ITmfContext context = seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
288 ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank());
289 return context;
290
291 }
292 return seekEvent(request.getIndex());
293 }
294
295 /**
296 * Return the next piece of data based on the context supplied. The context would typically be updated for the
297 * subsequent read.
298 *
299 * @param context
300 * @return
301 */
302 @SuppressWarnings("unchecked")
303 @Override
304 public T getNext(ITmfContext context) {
305 if (context instanceof TmfContext) {
306 return (T) getNextEvent((TmfContext) context);
307 }
308 return null;
309 }
310
311 // ------------------------------------------------------------------------
312 // ITmfTrace
313 // ------------------------------------------------------------------------
314
315 /* (non-Javadoc)
316 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
317 */
318 @Override
319 public TmfContext seekEvent(ITmfTimestamp timestamp) {
320
321 if (timestamp == null) {
322 timestamp = TmfTimestamp.BigBang;
323 }
324
325 // First, find the right checkpoint
326 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
327
328 // In the very likely case that the checkpoint was not found, bsearch
329 // returns its negated would-be location (not an offset...). From that
330 // index, we can then position the stream and get the event.
331 if (index < 0) {
332 index = Math.max(0, -(index + 2));
333 }
334
335 // Position the stream at the checkpoint
336 ITmfLocation<?> location;
337 synchronized (fCheckpoints) {
338 if (fCheckpoints.size() > 0) {
339 if (index >= fCheckpoints.size()) {
340 index = fCheckpoints.size() - 1;
341 }
342 location = fCheckpoints.elementAt(index).getLocation();
343 } else {
344 location = null;
345 }
346 }
347 TmfContext context = seekLocation(location);
348 context.setRank(index * fIndexPageSize);
349
350 // And locate the event
351 TmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype...
352 TmfEvent event = getNextEvent(nextEventContext);
353 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
354 context.setLocation(nextEventContext.getLocation().clone());
355 context.updateRank(1);
356 event = getNextEvent(nextEventContext);
357 }
358
359 return context;
360 }
361
362 /* (non-Javadoc)
363 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
364 */
365 @Override
366 public TmfContext seekEvent(long rank) {
367
368 // Position the stream at the previous checkpoint
369 int index = (int) rank / fIndexPageSize;
370 ITmfLocation<?> location;
371 synchronized (fCheckpoints) {
372 if (fCheckpoints.size() == 0) {
373 location = null;
374 } else {
375 if (index >= fCheckpoints.size()) {
376 index = fCheckpoints.size() - 1;
377 }
378 location = fCheckpoints.elementAt(index).getLocation();
379 }
380 }
381
382 TmfContext context = seekLocation(location);
383 long pos = index * fIndexPageSize;
384 context.setRank(pos);
385
386 if (pos < rank) {
387 TmfEvent event = getNextEvent(context);
388 while (event != null && ++pos < rank) {
389 event = getNextEvent(context);
390 }
391 }
392
393 return context;
394 }
395
396 /*
397 * (non-Javadoc)
398 *
399 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
400 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
401 */
402 @Override
403 public synchronized TmfEvent getNextEvent(TmfContext context) {
404 // parseEvent() does not update the context
405 TmfEvent event = parseEvent(context);
406 if (event != null) {
407 updateIndex(context, context.getRank(), event.getTimestamp());
408 context.setLocation(getCurrentLocation());
409 context.updateRank(1);
410 processEvent(event);
411 }
412 return event;
413 }
414
415 protected synchronized void updateIndex(ITmfContext context, long rank, ITmfTimestamp timestamp) {
416 if (fStartTime.compareTo(timestamp, false) > 0)
417 fStartTime = timestamp;
418 if (fEndTime.compareTo(timestamp, false) < 0)
419 fEndTime = timestamp;
420 if (context.isValidRank()) {
421 if (fNbEvents <= rank)
422 fNbEvents = rank + 1;
423 // Build the index as we go along
424 if ((rank % fIndexPageSize) == 0) {
425 // Determine the table position
426 long position = rank / fIndexPageSize;
427 // Add new entry at proper location (if empty)
428 if (fCheckpoints.size() == position) {
429 ITmfLocation<?> location = context.getLocation().clone();
430 fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location));
431 // System.out.println(getName() + "[" + (fCheckpoints.size()
432 // - 1) + "] " + timestamp + ", " + location.toString());
433 }
434 }
435 }
436 }
437
438 /**
439 * Hook for special processing by the concrete class (called by getNextEvent())
440 *
441 * @param event
442 */
443 protected void processEvent(TmfEvent event) {
444 // Do nothing by default
445 }
446
447 // ------------------------------------------------------------------------
448 // toString
449 // ------------------------------------------------------------------------
450
451 /* (non-Javadoc)
452 * @see java.lang.Object#toString()
453 */
454 @Override
455 @SuppressWarnings("nls")
456 public String toString() {
457 return "[TmfTrace (" + getName() + ")]";
458 }
459
460 // ------------------------------------------------------------------------
461 // Indexing
462 // ------------------------------------------------------------------------
463
464 /*
465 * The purpose of the index is to keep the information needed to rapidly
466 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
467 * event).
468 */
469
470 @SuppressWarnings({ "unchecked" })
471 protected void indexTrace(boolean waitForCompletion) {
472
473 final Job job = new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
474 @Override
475 protected IStatus run(IProgressMonitor monitor) {
476 while (!monitor.isCanceled()) {
477 try {
478 Thread.sleep(100);
479 } catch (InterruptedException e) {
480 return Status.OK_STATUS;
481 }
482 }
483 monitor.done();
484 return Status.OK_STATUS;
485 }
486 };
487 job.schedule();
488
489 fCheckpoints.clear();
490 ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, TmfDataRequest.ALL_DATA,
491 fIndexPageSize, ITmfDataRequest.ExecutionType.BACKGROUND) {
492
493 ITmfTimestamp startTime = null;
494 ITmfTimestamp lastTime = null;
495
496 @Override
497 public void handleData(TmfEvent event) {
498 super.handleData(event);
499 if (event != null) {
500 ITmfTimestamp ts = event.getTimestamp();
501 if (startTime == null)
502 startTime = ts.clone();
503 lastTime = ts.clone();
504
505 if ((getNbRead() % fIndexPageSize) == 0) {
506 updateTrace();
507 }
508 }
509 }
510
511 @Override
512 public void handleSuccess() {
513 updateTrace();
514 }
515
516 @Override
517 public void handleCompleted() {
518 job.cancel();
519 super.handleCompleted();
520 }
521
522 private void updateTrace() {
523 int nbRead = getNbRead();
524 if (nbRead != 0) {
525 fStartTime = startTime;
526 fEndTime = lastTime;
527 fNbEvents = nbRead;
528 notifyListeners();
529 }
530 }
531 };
532
533 sendRequest((ITmfDataRequest<T>) request);
534 if (waitForCompletion)
535 try {
536 request.waitForCompletion();
537 } catch (InterruptedException e) {
538 e.printStackTrace();
539 }
540 }
541
542 protected void notifyListeners() {
543 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
544 }
545 }
This page took 0.043749 seconds and 5 git commands to generate.