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