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