Refactor TmfTrace and dependencies - remove indexTrace()
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / TmfTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010, 2012 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 * Francois Chouinard - Updated as per TMF Trace Model 1.0
12 *******************************************************************************/
13
14 package org.eclipse.linuxtools.tmf.core.trace;
15
16 import java.io.File;
17 import java.io.FileNotFoundException;
18 import java.util.Collections;
19 import java.util.Vector;
20
21 import org.eclipse.core.resources.IProject;
22 import org.eclipse.core.resources.IResource;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.Path;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.core.runtime.jobs.Job;
28 import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider;
29 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
30 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
31 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
32 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
33 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
34 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
35 import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
36 import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
37 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
38
39 /**
40 * <b><u>TmfTrace</u></b>
41 * <p>
42 * Abstract implementation of ITmfTrace.
43 * <p>
44 * It should be sufficient to extend this class and provide implementations for
45 * <code>getCurrentLocation()</code> and <code>seekLocation()</code>, as well
46 * as a proper parser, to have a working concrete implementation.
47 */
48 public abstract class TmfTrace<T extends ITmfEvent> extends TmfEventProvider<T> implements ITmfTrace<T> {
49
50 // ------------------------------------------------------------------------
51 // Constants
52 // ------------------------------------------------------------------------
53
54 /**
55 * The default number of events in an index page. Can be used as block size.
56 */
57 public static final int DEFAULT_INDEX_PAGE_SIZE = 1000;
58
59 // ------------------------------------------------------------------------
60 // Attributes
61 // ------------------------------------------------------------------------
62
63 // The resource used for persistent properties for this trace
64 private IResource fResource;
65
66 // The trace path
67 private String fPath;
68
69 /**
70 * The cache page size AND checkpoints interval
71 */
72 protected int fIndexPageSize = DEFAULT_INDEX_PAGE_SIZE;
73
74 // The set of event stream checkpoints
75 protected Vector<TmfCheckpoint> fCheckpoints = new Vector<TmfCheckpoint>();
76
77 // The number of events collected
78 protected long fNbEvents = 0;
79
80 // The time span of the event stream
81 private ITmfTimestamp fStartTime = TmfTimestamp.BIG_CRUNCH;
82 private ITmfTimestamp fEndTime = TmfTimestamp.BIG_BANG;
83
84 /**
85 * The trace streaming interval (0 = no streaming)
86 */
87 protected long fStreamingInterval = 0;
88
89 // ------------------------------------------------------------------------
90 // Construction
91 // ------------------------------------------------------------------------
92
93 /**
94 * The default, parameterless, constructor
95 */
96 public TmfTrace() {
97 super();
98 }
99
100 /**
101 * The standard constructor (non-streaming trace)
102 *
103 * @param name the trace display name
104 * @param type the trace event type
105 * @param path the trace path
106 * @param pageSize the trace index page size
107 * @throws FileNotFoundException
108 */
109 protected TmfTrace(final IResource resource, final Class<T> type, final String path, final int indexPageSize) throws FileNotFoundException {
110 this(resource, type, path, 0, indexPageSize);
111 }
112
113 /**
114 * The full constructor
115 *
116 * @param name the trace display name
117 * @param type the trace event type
118 * @param path the trace path
119 * @param pageSize the trace index page size
120 * @throws FileNotFoundException
121 */
122 protected TmfTrace(final IResource resource, final Class<T> type, final String path, final long interval, final int indexPageSize) throws FileNotFoundException
123 {
124 super();
125 fStreamingInterval = interval;
126 fIndexPageSize = (indexPageSize > 0) ? indexPageSize : DEFAULT_INDEX_PAGE_SIZE;
127 initialize(resource, path, type);
128 }
129
130 /**
131 * Copy constructor
132 *
133 * @param trace the original trace
134 */
135 public TmfTrace(final ITmfTrace<T> trace) throws FileNotFoundException {
136 super();
137 if (trace == null)
138 throw new IllegalArgumentException();
139 fStreamingInterval = getStreamingInterval();
140 fIndexPageSize = getIndexPageSize();
141 initialize(trace.getResource(), trace.getPath(), trace.getType());
142 indexTrace(false);
143 }
144
145 // ------------------------------------------------------------------------
146 // ITmfTrace - Initializers
147 // ------------------------------------------------------------------------
148
149 /**
150 * @param resource
151 * @param path
152 * @param type
153 * @throws FileNotFoundException
154 */
155 protected void initialize(final IResource resource, final String path, final Class<T> type) throws FileNotFoundException {
156 fResource = resource;
157 fPath = path;
158 String traceName = (resource != null) ? resource.getName() : null;
159 // If no display name was provided, extract it from the trace path
160 if (traceName == null)
161 if (path != null) {
162 final int sep = path.lastIndexOf(Path.SEPARATOR);
163 traceName = (sep >= 0) ? path.substring(sep + 1) : path;
164 }
165 else {
166 traceName = ""; //$NON-NLS-1$
167 }
168 super.init(traceName, type);
169 }
170
171 /* (non-Javadoc)
172 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
173 */
174 @Override
175 public void initTrace(final IResource resource, final String path, final Class<T> type) throws FileNotFoundException {
176 initialize(resource, path, type);
177 indexTrace(false);
178 }
179
180 /* (non-Javadoc)
181 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
182 */
183 @Override
184 public boolean validate(final IProject project, final String path) {
185 final File file = new File(path);
186 return file.exists();
187 }
188
189 // ------------------------------------------------------------------------
190 // ITmfTrace - Basic getters
191 // ------------------------------------------------------------------------
192
193 /* (non-Javadoc)
194 * @see org.eclipse.linuxtools.tmf.core.component.TmfDataProvider#getType()
195 */
196 @Override
197 @SuppressWarnings("unchecked")
198 public Class<T> getType() {
199 return (Class<T>) super.getType();
200 }
201
202 /* (non-Javadoc)
203 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getResource()
204 */
205 @Override
206 public IResource getResource() {
207 return fResource;
208 }
209
210 /* (non-Javadoc)
211 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getPath()
212 */
213 @Override
214 public String getPath() {
215 return fPath;
216 }
217
218 // ------------------------------------------------------------------------
219 // ITmfTrace - Trace characteristics getters
220 // ------------------------------------------------------------------------
221
222 /* (non-Javadoc)
223 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getNbEvents()
224 */
225 @Override
226 public long getNbEvents() {
227 return fNbEvents;
228 }
229
230 /* (non-Javadoc)
231 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getTimeRange()
232 */
233 @Override
234 public TmfTimeRange getTimeRange() {
235 return new TmfTimeRange(fStartTime, fEndTime);
236 }
237
238 /* (non-Javadoc)
239 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getStartTime()
240 */
241 @Override
242 public ITmfTimestamp getStartTime() {
243 return new TmfTimestamp(fStartTime);
244 }
245
246 /* (non-Javadoc)
247 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getEndTime()
248 */
249 @Override
250 public ITmfTimestamp getEndTime() {
251 return new TmfTimestamp(fEndTime);
252 }
253
254 // ------------------------------------------------------------------------
255 // ITmfTrace - Seek operations (returning a reading context)
256 // ------------------------------------------------------------------------
257
258 /* (non-Javadoc)
259 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
260 */
261 @Override
262 public ITmfContext seekEvent(final ITmfTimestamp timestamp) {
263
264 // A null timestamp indicates to seek the first event
265 if (timestamp == null)
266 return seekLocation(null);
267
268 // Find the checkpoint at or before the requested timestamp.
269 // In the very likely event that the timestamp is not at a checkpoint
270 // boundary, bsearch will return index = (- (insertion point + 1)).
271 // It is then trivial to compute the index of the previous checkpoint.
272 int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));
273 if (index < 0) {
274 index = Math.max(0, -(index + 2));
275 }
276
277 // Position the trace at the checkpoint
278 final ITmfContext context = seekCheckpoint(index);
279
280 // And locate the requested event context
281 final ITmfContext nextEventContext = context.clone(); // Must use clone() to get the right subtype...
282 ITmfEvent event = getNextEvent(nextEventContext);
283 while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
284 context.setLocation(nextEventContext.getLocation().clone());
285 context.increaseRank();
286 event = getNextEvent(nextEventContext);
287 }
288 return context;
289 }
290
291 /* (non-Javadoc)
292 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(long)
293 */
294 @Override
295 public ITmfContext seekEvent(final long rank) {
296
297 // A rank <= 0 indicates to seek the first event
298 if (rank <= 0)
299 return seekLocation(null);
300
301 // Find the checkpoint at or before the requested rank.
302 final int index = (int) rank / fIndexPageSize;
303 final ITmfContext context = seekCheckpoint(index);
304
305 // And locate the requested event context
306 long pos = context.getRank();
307 if (pos < rank) {
308 ITmfEvent event = getNextEvent(context);
309 while (event != null && ++pos < rank) {
310 event = getNextEvent(context);
311 }
312 }
313 return context;
314 }
315
316
317 /**
318 * Position the trace at the given checkpoint
319 *
320 * @param index the checkpoint index
321 * @return the corresponding context
322 */
323 private ITmfContext seekCheckpoint(int index) {
324 ITmfLocation<?> location;
325 synchronized (fCheckpoints) {
326 if (!fCheckpoints.isEmpty()) {
327 if (index >= fCheckpoints.size()) {
328 index = fCheckpoints.size() - 1;
329 }
330 location = fCheckpoints.elementAt(index).getLocation();
331 } else {
332 location = null;
333 }
334 }
335 final ITmfContext context = seekLocation(location);
336 context.setRank(index * fIndexPageSize);
337 return context;
338 }
339
340 // ------------------------------------------------------------------------
341 // ITmfTrace - Read operations (returning an actual event)
342 // ------------------------------------------------------------------------
343
344 /* (non-Javadoc)
345 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getNextEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
346 */
347 @Override
348 public synchronized ITmfEvent getNextEvent(final ITmfContext context) {
349 // parseEvent() does not update the context
350 final ITmfEvent event = parseEvent(context);
351 if (event != null) {
352 updateIndex(context, context.getRank(), event.getTimestamp());
353 context.setLocation(getCurrentLocation());
354 context.increaseRank();
355 processEvent(event);
356 }
357 return event;
358 }
359
360 /**
361 * Hook for special processing by the concrete class (called by
362 * getNextEvent())
363 *
364 * @param event
365 */
366 protected void processEvent(final ITmfEvent event) {
367 // Do nothing by default
368 }
369
370 protected synchronized void updateIndex(final ITmfContext context, final long rank, final ITmfTimestamp timestamp) {
371 if (fStartTime.compareTo(timestamp, false) > 0) {
372 fStartTime = timestamp;
373 }
374 if (fEndTime.compareTo(timestamp, false) < 0) {
375 fEndTime = timestamp;
376 }
377 if (context.hasValidRank()) {
378 if (fNbEvents <= rank) {
379 fNbEvents = rank + 1;
380 }
381 // Build the index as we go along
382 if ((rank % fIndexPageSize) == 0) {
383 // Determine the table position
384 final long position = rank / fIndexPageSize;
385 // Add new entry at proper location (if empty)
386 if (fCheckpoints.size() == position) {
387 final ITmfLocation<?> location = context.getLocation().clone();
388 fCheckpoints.add(new TmfCheckpoint(timestamp.clone(), location));
389 // System.out.println(getName() + "[" + (fCheckpoints.size() + "] " + timestamp + ", " + location.toString());
390 }
391 }
392 }
393 }
394
395 // ------------------------------------------------------------------------
396 // ITmfTrace - indexing
397 // ------------------------------------------------------------------------
398
399 /*
400 * The index is a list of contexts that point to events at regular interval
401 * (rank-wise) in the trace. After it is built, the index can be used to
402 * quickly access any event by rank or timestamp.
403 *
404 * fIndexPageSize holds the event interval (default INDEX_PAGE_SIZE).
405 */
406
407 @SuppressWarnings({ "unchecked" })
408 protected void indexTrace(final boolean waitForCompletion) {
409
410 // The monitoring job
411 final Job job = new Job("Indexing " + getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
412
413 @Override
414 protected IStatus run(final IProgressMonitor monitor) {
415 while (!monitor.isCanceled()) {
416 try {
417 Thread.sleep(100);
418 } catch (final InterruptedException e) {
419 return Status.OK_STATUS;
420 }
421 }
422 monitor.done();
423 return Status.OK_STATUS;
424 }
425 };
426 job.schedule();
427
428 // Clear the checkpoints
429 fCheckpoints.clear();
430
431 // Build a background request for all the trace data. The index is
432 // updated as we go by getNextEvent().
433 final ITmfEventRequest<ITmfEvent> request = new TmfEventRequest<ITmfEvent>(ITmfEvent.class,
434 TmfTimeRange.ETERNITY,
435 TmfDataRequest.ALL_DATA, fIndexPageSize, ITmfDataRequest.ExecutionType.BACKGROUND)
436 {
437
438 ITmfTimestamp startTime = null;
439 ITmfTimestamp lastTime = null;
440
441 @Override
442 public void handleData(final ITmfEvent event) {
443 super.handleData(event);
444 if (event != null) {
445 final ITmfTimestamp timestamp = event.getTimestamp();
446 if (startTime == null) {
447 startTime = timestamp.clone();
448 }
449 lastTime = timestamp.clone();
450
451 // Update the trace status at regular intervals
452 if ((getNbRead() % fIndexPageSize) == 0) {
453 updateTraceStatus();
454 }
455 }
456 }
457
458 @Override
459 public void handleSuccess() {
460 updateTraceStatus();
461 }
462
463 @Override
464 public void handleCompleted() {
465 job.cancel();
466 super.handleCompleted();
467 }
468
469 private synchronized void updateTraceStatus() {
470 final int nbRead = getNbRead();
471 if (nbRead != 0) {
472 fStartTime = startTime;
473 fEndTime = lastTime;
474 fNbEvents = nbRead;
475 notifyListeners();
476 }
477 }
478 };
479
480 // Submit the request and wait for completion if required
481 sendRequest((ITmfDataRequest<T>) request);
482 if (waitForCompletion) {
483 try {
484 request.waitForCompletion();
485 } catch (final InterruptedException e) {
486 }
487 }
488 }
489
490 private void notifyListeners() {
491 broadcast(new TmfTraceUpdatedSignal(this, this, new TmfTimeRange(fStartTime, fEndTime)));
492 }
493
494 // ------------------------------------------------------------------------
495 // Operations
496 // ------------------------------------------------------------------------
497
498 @SuppressWarnings("unchecked")
499 public Vector<TmfCheckpoint> getCheckpoints() {
500 return (Vector<TmfCheckpoint>) fCheckpoints.clone();
501 }
502
503 // ------------------------------------------------------------------------
504 // Operators
505 // ------------------------------------------------------------------------
506
507 protected void setTimeRange(final TmfTimeRange range) {
508 fStartTime = range.getStartTime();
509 fEndTime = range.getEndTime();
510 }
511
512 protected void setStartTime(final ITmfTimestamp startTime) {
513 fStartTime = startTime;
514 }
515
516 protected void setEndTime(final ITmfTimestamp endTime) {
517 fEndTime = endTime;
518 }
519
520 // ------------------------------------------------------------------------
521 // TmfProvider
522 // ------------------------------------------------------------------------
523
524 @Override
525 public ITmfContext armRequest(final ITmfDataRequest<T> request) {
526 if (request instanceof ITmfEventRequest<?>
527 && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest<T>) request).getRange().getStartTime())
528 && request.getIndex() == 0) {
529 final ITmfContext context = seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
530 ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank());
531 return context;
532
533 }
534 return seekEvent(request.getIndex());
535 }
536
537 /**
538 * Return the next piece of data based on the context supplied. The context
539 * would typically be updated for the subsequent read.
540 *
541 * @param context
542 * @return the event referred to by context
543 */
544 @SuppressWarnings("unchecked")
545 @Override
546 public T getNext(final ITmfContext context) {
547 if (context instanceof TmfContext)
548 return (T) getNextEvent(context);
549 return null;
550 }
551
552
553 // ------------------------------------------------------------------------
554 // toString
555 // ------------------------------------------------------------------------
556
557 /*
558 * (non-Javadoc)
559 *
560 * @see java.lang.Object#toString()
561 */
562 @Override
563 @SuppressWarnings("nls")
564 public String toString() {
565 return "[TmfTrace (" + getName() + ")]";
566 }
567
568 // ------------------------------------------------------------------------
569 // ITmfTrace - Trace TBD getters
570 // ------------------------------------------------------------------------
571
572 /* (non-Javadoc)
573 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getStreamingInterval()
574 */
575 @Override
576 public long getStreamingInterval() {
577 return fStreamingInterval;
578 }
579
580 /* (non-Javadoc)
581 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getIndexPageSize()
582 */
583 @Override
584 public int getIndexPageSize() {
585 return fIndexPageSize;
586 }
587
588 }
This page took 0.043601 seconds and 6 git commands to generate.