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