Merge branch 'master' into lttng_2_0_control_dev
[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.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.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 TmfTimestamp fStartTime = TmfTimestamp.BigCrunch;
85 private TmfTimestamp fEndTime = TmfTimestamp.BigBang;
86
87 // The trace resource
88 private IResource fResource;
89
90 // ------------------------------------------------------------------------
91 // Constructors
92 // ------------------------------------------------------------------------
93
94 public TmfTrace() {
95 super();
96 }
97
98 @Override
99 public void initTrace(String path, Class<T> eventType) throws FileNotFoundException {
100 initTmfTrace(path, eventType, DEFAULT_INDEX_PAGE_SIZE, false, null);
101 }
102
103 @Override
104 public void initTrace(String path, Class<T> eventType, int cacheSize) throws FileNotFoundException {
105 initTmfTrace(path, eventType, cacheSize, false, null);
106 }
107
108 @Override
109 public void initTrace(String path, Class<T> eventType, boolean indexTrace) throws FileNotFoundException {
110 initTmfTrace(path, eventType, DEFAULT_INDEX_PAGE_SIZE, indexTrace, null);
111 }
112
113 @Override
114 public void initTrace(String path, Class<T> eventType, int cacheSize, boolean indexTrace) throws FileNotFoundException {
115 initTmfTrace(path, eventType, cacheSize, indexTrace, null);
116 }
117
118 @Override
119 public void initTrace(String path, Class<T> eventType, int cacheSize, boolean indexTrace, String name) throws FileNotFoundException {
120 initTmfTrace(path, eventType, cacheSize, indexTrace, name);
121 }
122
123 private void initTmfTrace(String path, Class<T> eventType, int cacheSize, boolean indexTrace, String name) throws FileNotFoundException {
124 fPath = path;
125 if (name != null) {
126 fTraceName = name;
127 }
128 if (fTraceName == null) {
129 fTraceName = ""; //$NON-NLS-1$
130 if (path != null) {
131 int sep = path.lastIndexOf(Path.SEPARATOR);
132 fTraceName = (sep >= 0) ? path.substring(sep + 1) : path;
133 }
134 }
135 super.init(fTraceName, eventType);
136 fIndexPageSize = (cacheSize > 0) ? cacheSize : DEFAULT_INDEX_PAGE_SIZE;
137 if (indexTrace)
138 indexTrace(false);
139 }
140
141 @Override
142 public boolean validate(IProject project, String path) {
143 File file = new File(path);
144 return file.exists();
145 }
146
147 /**
148 * @param path
149 * @throws FileNotFoundException
150 */
151 protected TmfTrace(String name, Class<T> type, String path) throws FileNotFoundException {
152 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE, true);
153 }
154
155 /**
156 * @param path
157 * @param cacheSize
158 * @throws FileNotFoundException
159 */
160 protected TmfTrace(String name, Class<T> type, String path, int cacheSize) throws FileNotFoundException {
161 this(name, type, path, cacheSize, true);
162 }
163
164 /**
165 * @param path
166 * @param indexTrace
167 * @throws FileNotFoundException
168 */
169 protected TmfTrace(String name, Class<T> type, String path, boolean indexTrace) throws FileNotFoundException {
170 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE, indexTrace);
171 }
172
173 /**
174 * @param path
175 * @param cacheSize
176 * @param indexTrace
177 * @throws FileNotFoundException
178 */
179 protected TmfTrace(String name, Class<T> type, String path, int cacheSize, boolean indexTrace) throws FileNotFoundException {
180 super();
181 fTraceName = name;
182 initTrace(path, type, cacheSize, indexTrace);
183 }
184
185 @SuppressWarnings("unchecked")
186 @Override
187 public TmfTrace<T> clone() throws CloneNotSupportedException {
188 TmfTrace<T> clone = (TmfTrace<T>) super.clone();
189 clone.fCheckpoints = fCheckpoints;
190 clone.fStartTime = new TmfTimestamp(fStartTime);
191 clone.fEndTime = new TmfTimestamp(fEndTime);
192 return clone;
193 }
194
195 // ------------------------------------------------------------------------
196 // Accessors
197 // ------------------------------------------------------------------------
198
199 /**
200 * @return the trace path
201 */
202 @Override
203 public String getPath() {
204 return fPath;
205 }
206
207 /* (non-Javadoc)
208 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
209 */
210 @Override
211 public long getNbEvents() {
212 return fNbEvents;
213 }
214
215 /**
216 * @return the size of the cache
217 */
218 @Override
219 public int getCacheSize() {
220 return fIndexPageSize;
221 }
222
223 /* (non-Javadoc)
224 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
225 */
226 @Override
227 public TmfTimeRange getTimeRange() {
228 return new TmfTimeRange(fStartTime, fEndTime);
229 }
230
231 /* (non-Javadoc)
232 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
233 */
234 @Override
235 public TmfTimestamp getStartTime() {
236 return fStartTime;
237 }
238
239 /* (non-Javadoc)
240 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
241 */
242 @Override
243 public TmfTimestamp getEndTime() {
244 return fEndTime;
245 }
246
247 /* (non-Javadoc)
248 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
249 */
250 @Override
251 public long getStreamingInterval() {
252 return 0;
253 }
254
255 @SuppressWarnings("unchecked")
256 public Vector<TmfCheckpoint> getCheckpoints() {
257 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
258 }
259
260 /**
261 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
262 * (if any).
263 *
264 * @param timestamp
265 * @return
266 */
267 @Override
268 public long getRank(TmfTimestamp timestamp) {
269 TmfContext context = seekEvent(timestamp);
270 return context.getRank();
271 }
272
273 // ------------------------------------------------------------------------
274 // Operators
275 // ------------------------------------------------------------------------
276
277 protected void setTimeRange(TmfTimeRange range) {
278 fStartTime = range.getStartTime();
279 fEndTime = range.getEndTime();
280 }
281
282 protected void setStartTime(TmfTimestamp startTime) {
283 fStartTime = startTime;
284 }
285
286 protected void setEndTime(TmfTimestamp endTime) {
287 fEndTime = endTime;
288 }
289
290 // ------------------------------------------------------------------------
291 // TmfProvider
292 // ------------------------------------------------------------------------
293
294 @Override
295 public ITmfContext armRequest(ITmfDataRequest<T> request) {
296 if (request instanceof ITmfEventRequest<?>
297 && !TmfTimestamp.BigBang.equals(((ITmfEventRequest<T>) request).getRange().getStartTime()) && request.getIndex() == 0) {
298 ITmfContext context = seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
299 ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank());
300 return context;
301
302 }
303 return seekEvent(request.getIndex());
304 }
305
306 /**
307 * Return the next piece of data based on the context supplied. The context would typically be updated for the
308 * subsequent read.
309 *
310 * @param context
311 * @return
312 */
313 @SuppressWarnings("unchecked")
314 @Override
315 public T getNext(ITmfContext context) {
316 if (context instanceof TmfContext) {
317 return (T) getNextEvent((TmfContext) context);
318 }
319 return null;
320 }
321
322 // ------------------------------------------------------------------------
323 // ITmfTrace
324 // ------------------------------------------------------------------------
325
326 /* (non-Javadoc)
327 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
328 */
329 @Override
330 public TmfContext seekEvent(TmfTimestamp timestamp) {
331
332 if (timestamp == null) {
333 timestamp = TmfTimestamp.BigBang;
334 }
335
336 // First, find the right checkpoint
337 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
338
339 // In the very likely case that the checkpoint was not found, bsearch
340 // returns its negated would-be location (not an offset...). From that
341 // index, we can then position the stream and get the event.
342 if (index < 0) {
343 index = Math.max(0, -(index + 2));
344 }
345
346 // Position the stream at the checkpoint
347 ITmfLocation<?> location;
348 synchronized (fCheckpoints) {
349 if (fCheckpoints.size() > 0) {
350 if (index >= fCheckpoints.size()) {
351 index = fCheckpoints.size() - 1;
352 }
353 location = fCheckpoints.elementAt(index).getLocation();
354 } else {
355 location = null;
356 }
357 }
358 TmfContext context = seekLocation(location);
359 context.setRank(index * fIndexPageSize);
360
361 // And locate the event
362 TmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype...
363 TmfEvent event = getNextEvent(nextEventContext);
364 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
365 context.setLocation(nextEventContext.getLocation().clone());
366 context.updateRank(1);
367 event = getNextEvent(nextEventContext);
368 }
369
370 return context;
371 }
372
373 /* (non-Javadoc)
374 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(int)
375 */
376 @Override
377 public TmfContext seekEvent(long rank) {
378
379 // Position the stream at the previous checkpoint
380 int index = (int) rank / fIndexPageSize;
381 ITmfLocation<?> location;
382 synchronized (fCheckpoints) {
383 if (fCheckpoints.size() == 0) {
384 location = null;
385 } else {
386 if (index >= fCheckpoints.size()) {
387 index = fCheckpoints.size() - 1;
388 }
389 location = fCheckpoints.elementAt(index).getLocation();
390 }
391 }
392
393 TmfContext context = seekLocation(location);
394 long pos = index * fIndexPageSize;
395 context.setRank(pos);
396
397 if (pos < rank) {
398 TmfEvent event = getNextEvent(context);
399 while (event != null && ++pos < rank) {
400 event = getNextEvent(context);
401 }
402 }
403
404 return context;
405 }
406
407 /*
408 * (non-Javadoc)
409 *
410 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getNextEvent(org.eclipse.
411 * linuxtools.tmf.trace.ITmfTrace.TraceContext)
412 */
413 @Override
414 public synchronized TmfEvent getNextEvent(TmfContext context) {
415 // parseEvent() does not update the context
416 TmfEvent event = parseEvent(context);
417 if (event != null) {
418 updateIndex(context, context.getRank(), event.getTimestamp());
419 context.setLocation(getCurrentLocation());
420 context.updateRank(1);
421 processEvent(event);
422 }
423 return event;
424 }
425
426 protected synchronized void updateIndex(ITmfContext context, long rank, TmfTimestamp timestamp) {
427 if (fStartTime.compareTo(timestamp, false) > 0)
428 fStartTime = timestamp;
429 if (fEndTime.compareTo(timestamp, false) < 0)
430 fEndTime = timestamp;
431 if (context.isValidRank()) {
432 if (fNbEvents <= rank)
433 fNbEvents = rank + 1;
434 // Build the index as we go along
435 if ((rank % fIndexPageSize) == 0) {
436 // Determine the table position
437 long position = rank / fIndexPageSize;
438 // Add new entry at proper location (if empty)
439 if (fCheckpoints.size() == position) {
440 ITmfLocation<?> location = context.getLocation().clone();
441 fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location));
442 // System.out.println(getName() + "[" + (fCheckpoints.size()
443 // - 1) + "] " + timestamp + ", " + location.toString());
444 }
445 }
446 }
447 }
448
449 /**
450 * Hook for special processing by the concrete class (called by getNextEvent())
451 *
452 * @param event
453 */
454 protected void processEvent(TmfEvent event) {
455 // Do nothing by default
456 }
457
458 // ------------------------------------------------------------------------
459 // toString
460 // ------------------------------------------------------------------------
461
462 /* (non-Javadoc)
463 * @see java.lang.Object#toString()
464 */
465 @Override
466 @SuppressWarnings("nls")
467 public String toString() {
468 return "[TmfTrace (" + getName() + ")]";
469 }
470
471 // ------------------------------------------------------------------------
472 // Indexing
473 // ------------------------------------------------------------------------
474
475 /*
476 * The purpose of the index is to keep the information needed to rapidly
477 * restore the traces contexts at regular intervals (every INDEX_PAGE_SIZE
478 * event).
479 */
480
481 @SuppressWarnings({ "unchecked" })
482 protected void indexTrace(boolean waitForCompletion) {
483
484 final Job job = new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
485 @Override
486 protected IStatus run(IProgressMonitor monitor) {
487 while (!monitor.isCanceled()) {
488 try {
489 Thread.sleep(100);
490 } catch (InterruptedException e) {
491 return Status.OK_STATUS;
492 }
493 }
494 monitor.done();
495 return Status.OK_STATUS;
496 }
497 };
498 job.schedule();
499
500 fCheckpoints.clear();
501 ITmfEventRequest<TmfEvent> request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, TmfDataRequest.ALL_DATA,
502 fIndexPageSize, ITmfDataRequest.ExecutionType.BACKGROUND) {
503
504 TmfTimestamp startTime = null;
505 TmfTimestamp lastTime = null;
506
507 @Override
508 public void handleData(TmfEvent event) {
509 super.handleData(event);
510 if (event != null) {
511 TmfTimestamp ts = event.getTimestamp();
512 if (startTime == null)
513 startTime = new TmfTimestamp(ts);
514 lastTime = new TmfTimestamp(ts);
515
516 if ((getNbRead() % fIndexPageSize) == 0) {
517 updateTrace();
518 }
519 }
520 }
521
522 @Override
523 public void handleSuccess() {
524 updateTrace();
525 }
526
527 @Override
528 public void handleCompleted() {
529 job.cancel();
530 super.handleCompleted();
531 }
532
533 private void updateTrace() {
534 int nbRead = getNbRead();
535 if (nbRead != 0) {
536 fStartTime = startTime;
537 fEndTime = lastTime;
538 fNbEvents = nbRead;
539 notifyListeners();
540 }
541 }
542 };
543
544 sendRequest((ITmfDataRequest<T>) request);
545 if (waitForCompletion)
546 try {
547 request.waitForCompletion();
548 } catch (InterruptedException e) {
549 e.printStackTrace();
550 }
551 }
552
553 protected void notifyListeners() {
554 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
555 }
556
557 /**
558 * Set the resource to be used for bookmarks on this trace
559 * @param resource the bookmarks resource
560 */
561 public void setResource(IResource resource) {
562 fResource = resource;
563 }
564
565 /**
566 * Get the resource used for bookmarks on this trace
567 * @return the bookmarks resource or null if none is set
568 */
569 public IResource getResource() {
570 return fResource;
571 }
572 }
This page took 0.045429 seconds and 6 git commands to generate.