Finalize ITmfTrace 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.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 fPath = path;
102 if (name != null) {
103 fTraceName = name;
104 }
105 if (fTraceName == null) {
106 fTraceName = ""; //$NON-NLS-1$
107 if (path != null) {
108 int sep = path.lastIndexOf(Path.SEPARATOR);
109 fTraceName = (sep >= 0) ? path.substring(sep + 1) : path;
110 }
111 }
112 super.init(fTraceName, eventType);
113 }
114
115 @Override
116 public boolean validate(IProject project, String path) {
117 File file = new File(path);
118 return file.exists();
119 }
120
121 /**
122 * @param path
123 * @throws FileNotFoundException
124 */
125 protected TmfTrace(String name, Class<T> type, String path) throws FileNotFoundException {
126 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE, true);
127 }
128
129 /**
130 * @param path
131 * @param cacheSize
132 * @throws FileNotFoundException
133 */
134 protected TmfTrace(String name, Class<T> type, String path, int cacheSize) throws FileNotFoundException {
135 this(name, type, path, cacheSize, true);
136 }
137
138 /**
139 * @param path
140 * @param indexTrace
141 * @throws FileNotFoundException
142 */
143 protected TmfTrace(String name, Class<T> type, String path, boolean indexTrace) throws FileNotFoundException {
144 this(name, type, path, DEFAULT_INDEX_PAGE_SIZE, indexTrace);
145 }
146
147 /**
148 * @param path
149 * @param cacheSize
150 * @param indexTrace
151 * @throws FileNotFoundException
152 */
153 protected TmfTrace(String name, Class<T> type, String path, int indexPageSize, boolean indexTrace) throws FileNotFoundException {
154 super();
155 initTrace(name, path, type);
156 fIndexPageSize = (indexPageSize >0) ? indexPageSize : DEFAULT_INDEX_PAGE_SIZE;
157 if (indexTrace)
158 indexTrace(false);
159 }
160
161 @SuppressWarnings("unchecked")
162 @Override
163 public TmfTrace<T> clone() throws CloneNotSupportedException {
164 TmfTrace<T> clone = (TmfTrace<T>) super.clone();
165 clone.fCheckpoints = fCheckpoints;
166 clone.fStartTime = fStartTime.clone();
167 clone.fEndTime = fEndTime.clone();
168 return clone;
169 }
170
171 // ------------------------------------------------------------------------
172 // Accessors
173 // ------------------------------------------------------------------------
174
175 /**
176 * @return the trace path
177 */
178 @Override
179 public String getPath() {
180 return fPath;
181 }
182
183 /* (non-Javadoc)
184 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getNbEvents()
185 */
186 @Override
187 public synchronized long getNbEvents() {
188 return fNbEvents;
189 }
190
191 /**
192 * @return the size of the cache
193 */
194 @Override
195 public int getIndexPageSize() {
196 return fIndexPageSize;
197 }
198
199 /* (non-Javadoc)
200 * @see org.eclipse.linuxtools.tmf.stream.ITmfEventStream#getTimeRange()
201 */
202 @Override
203 public TmfTimeRange getTimeRange() {
204 return new TmfTimeRange(fStartTime, fEndTime);
205 }
206
207 /* (non-Javadoc)
208 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStartTime()
209 */
210 @Override
211 public ITmfTimestamp getStartTime() {
212 return fStartTime;
213 }
214
215 /* (non-Javadoc)
216 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getEndTime()
217 */
218 @Override
219 public ITmfTimestamp getEndTime() {
220 return fEndTime;
221 }
222
223 /* (non-Javadoc)
224 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
225 */
226 @Override
227 public long getStreamingInterval() {
228 return 0;
229 }
230
231 @SuppressWarnings("unchecked")
232 public Vector<TmfCheckpoint> getCheckpoints() {
233 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
234 }
235
236 /**
237 * Returns the rank of the first event with the requested timestamp. If none, returns the index of the next event
238 * (if any).
239 *
240 * @param timestamp the requested event timestamp
241 * @return the corresponding event rank
242 */
243 @Override
244 public long getRank(ITmfTimestamp timestamp) {
245 TmfContext context = seekEvent(timestamp);
246 return context.getRank();
247 }
248
249 // ------------------------------------------------------------------------
250 // Operators
251 // ------------------------------------------------------------------------
252
253 protected void setTimeRange(TmfTimeRange range) {
254 fStartTime = range.getStartTime();
255 fEndTime = range.getEndTime();
256 }
257
258 protected void setStartTime(ITmfTimestamp startTime) {
259 fStartTime = startTime;
260 }
261
262 protected void setEndTime(ITmfTimestamp endTime) {
263 fEndTime = endTime;
264 }
265
266 // ------------------------------------------------------------------------
267 // TmfProvider
268 // ------------------------------------------------------------------------
269
270 @Override
271 public ITmfContext armRequest(ITmfDataRequest<T> request) {
272 if (request instanceof ITmfEventRequest<?>
273 && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest<T>) request).getRange().getStartTime()) && request.getIndex() == 0) {
274 ITmfContext context = seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
275 ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank());
276 return context;
277
278 }
279 return seekEvent(request.getIndex());
280 }
281
282 /**
283 * Return the next piece of data based on the context supplied. The context would typically be updated for the
284 * subsequent read.
285 *
286 * @param context
287 * @return the event referred to by context
288 */
289 @SuppressWarnings("unchecked")
290 @Override
291 public T getNext(ITmfContext context) {
292 if (context instanceof TmfContext) {
293 return (T) getNextEvent((TmfContext) context);
294 }
295 return null;
296 }
297
298 // ------------------------------------------------------------------------
299 // ITmfTrace
300 // ------------------------------------------------------------------------
301
302 @Override
303 public abstract TmfContext seekLocation(ITmfLocation<?> location);
304
305 /* (non-Javadoc)
306 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.event.TmfTimestamp)
307 */
308 @Override
309 public TmfContext seekEvent(ITmfTimestamp ts) {
310
311 ITmfTimestamp timestamp = ts;
312 if (timestamp == null) {
313 timestamp = TmfTimestamp.BIG_BANG;
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.isEmpty()) {
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 ITmfEvent 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.isEmpty()) {
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 ITmfEvent 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 ITmfEvent getNextEvent(ITmfContext context) {
395 // parseEvent() does not update the context
396 ITmfEvent 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, ITmfTimestamp 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(ITmfEvent 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 @Override
462 @SuppressWarnings({ "unchecked" })
463 public void indexTrace(boolean waitForCompletion) {
464
465 final Job job = new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
466 @Override
467 protected IStatus run(IProgressMonitor monitor) {
468 while (!monitor.isCanceled()) {
469 try {
470 Thread.sleep(100);
471 } catch (InterruptedException e) {
472 return Status.OK_STATUS;
473 }
474 }
475 monitor.done();
476 return Status.OK_STATUS;
477 }
478 };
479 job.schedule();
480
481 fCheckpoints.clear();
482 ITmfEventRequest<ITmfEvent> request = new TmfEventRequest<ITmfEvent>(ITmfEvent.class, TmfTimeRange.ETERNITY, TmfDataRequest.ALL_DATA,
483 fIndexPageSize, ITmfDataRequest.ExecutionType.BACKGROUND) {
484
485 ITmfTimestamp startTime = null;
486 ITmfTimestamp lastTime = null;
487
488 @Override
489 public void handleData(ITmfEvent event) {
490 super.handleData(event);
491 if (event != null) {
492 ITmfTimestamp ts = event.getTimestamp();
493 if (startTime == null)
494 startTime = ts.clone();
495 lastTime = ts.clone();
496
497 if ((getNbRead() % fIndexPageSize) == 0) {
498 updateTrace();
499 }
500 }
501 }
502
503 @Override
504 public void handleSuccess() {
505 updateTrace();
506 }
507
508 @Override
509 public void handleCompleted() {
510 job.cancel();
511 super.handleCompleted();
512 }
513
514 private synchronized void updateTrace() {
515 int nbRead = getNbRead();
516 if (nbRead != 0) {
517 fStartTime = startTime;
518 fEndTime = lastTime;
519 fNbEvents = nbRead;
520 notifyListeners();
521 }
522 }
523 };
524
525 sendRequest((ITmfDataRequest<T>) request);
526 if (waitForCompletion)
527 try {
528 request.waitForCompletion();
529 } catch (InterruptedException e) {
530 // e.printStackTrace();
531 }
532 }
533
534 protected void notifyListeners() {
535 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
536 }
537
538 /*
539 * (non-Javadoc)
540 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#setResource(org.eclipse.core.resources.IResource)
541 */
542 @Override
543 public void setResource(IResource resource) {
544 fResource = resource;
545 }
546
547 /*
548 * (non-Javadoc)
549 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
550 */
551 @Override
552 public IResource getResource() {
553 return fResource;
554 }
555 }
This page took 0.051439 seconds and 6 git commands to generate.