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