Implement index cancellation on dispose (bug 381115)
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / TmfExperiment.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 org.eclipse.core.resources.IFile;
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.IResource;
19 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentContext;
20 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfExperimentLocation;
21 import org.eclipse.linuxtools.internal.tmf.core.trace.TmfLocationArray;
22 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
23 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
24 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
25 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
26 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
27 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
28 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
29 import org.eclipse.linuxtools.tmf.core.signal.TmfEndSynchSignal;
30 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;
31 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
32 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
33 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
34 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
35 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
36
37 /**
38 * TmfExperiment presents a time-ordered, unified view of a set of ITmfTrace:s
39 * that are part of a tracing experiment.
40 *
41 * @version 1.0
42 * @author Francois Chouinard
43 */
44 public class TmfExperiment<T extends ITmfEvent> extends TmfTrace<T> implements ITmfEventParser<T> {
45
46 // ------------------------------------------------------------------------
47 // Constants
48 // ------------------------------------------------------------------------
49
50 /**
51 * The default index page size
52 */
53 public static final int DEFAULT_INDEX_PAGE_SIZE = 5000;
54
55 // ------------------------------------------------------------------------
56 // Attributes
57 // ------------------------------------------------------------------------
58
59 /**
60 * The currently selected experiment (null if none)
61 */
62 protected static TmfExperiment<?> fCurrentExperiment = null;
63
64 /**
65 * The set of traces that constitute the experiment
66 */
67 protected ITmfTrace<T>[] fTraces;
68
69 /**
70 * The set of traces that constitute the experiment
71 */
72 private boolean fInitialized = false;
73
74 /**
75 * The experiment bookmarks file
76 */
77 private IFile fBookmarksFile;
78
79
80 // Saved experiment context (optimization)
81 private TmfExperimentContext fExperimentContext;
82
83 // ------------------------------------------------------------------------
84 // Construction
85 // ------------------------------------------------------------------------
86
87 /**
88 * @param type
89 * @param id
90 * @param traces
91 * @throws TmfTraceException
92 */
93 public TmfExperiment(final Class<T> type, final String id, final ITmfTrace<T>[] traces) {
94 this(type, id, traces, DEFAULT_INDEX_PAGE_SIZE);
95 }
96
97 /**
98 * @param type
99 * @param id
100 * @param traces
101 * @param indexPageSize
102 * @throws TmfTraceException
103 */
104 @SuppressWarnings({ "unchecked", "rawtypes" })
105 public TmfExperiment(final Class<T> type, final String path, final ITmfTrace<T>[] traces, final int indexPageSize) {
106 setCacheSize(indexPageSize);
107 setStreamingInterval(0);
108 setIndexer(new TmfCheckpointIndexer(this, indexPageSize));
109 setParser(this);
110 try {
111 super.initialize(null, path, type);
112 } catch (TmfTraceException e) {
113 e.printStackTrace();
114 }
115
116 fTraces = traces;
117 setTimeRange(TmfTimeRange.NULL_RANGE);
118 }
119
120 /**
121 * Clears the experiment
122 */
123 @Override
124 @SuppressWarnings("rawtypes")
125 public synchronized void dispose() {
126
127 final TmfExperimentDisposedSignal<T> signal = new TmfExperimentDisposedSignal<T>(this, this);
128 broadcast(signal);
129
130 if (fCurrentExperiment == this) {
131 fCurrentExperiment = null;
132 }
133
134 // Clean up the index
135 getIndexer().dispose();
136
137 if (fTraces != null) {
138 for (final ITmfTrace trace : fTraces)
139 trace.dispose();
140 fTraces = null;
141 }
142 super.dispose();
143 }
144
145 // ------------------------------------------------------------------------
146 // ITmfTrace - Initializers
147 // ------------------------------------------------------------------------
148
149 /* (non-Javadoc)
150 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#validate(org.eclipse.core.resources.IProject, java.lang.String)
151 */
152 @Override
153 public boolean validate(final IProject project, final String path) {
154 return true;
155 }
156
157 /* (non-Javadoc)
158 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#initTrace(org.eclipse.core.resources.IResource, java.lang.String, java.lang.Class)
159 */
160 @Override
161 public void initTrace(final IResource resource, final String path, final Class<T> type) {
162 }
163
164 // ------------------------------------------------------------------------
165 // Accessors
166 // ------------------------------------------------------------------------
167
168 /**
169 * Selects the current, framework-wide, experiment
170 *
171 * @param experiment das experiment
172 */
173 public static void setCurrentExperiment(final TmfExperiment<?> experiment) {
174 if (fCurrentExperiment != null && fCurrentExperiment != experiment) {
175 fCurrentExperiment.dispose();
176 }
177 fCurrentExperiment = experiment;
178 }
179
180 /**
181 * @return das experiment
182 */
183 public static TmfExperiment<?> getCurrentExperiment() {
184 return fCurrentExperiment;
185 }
186
187 /**
188 * Get the list of traces. Handle with care...
189 *
190 * @return the experiment traces
191 */
192 public ITmfTrace<T>[] getTraces() {
193 return fTraces;
194 }
195
196 /**
197 * Returns the timestamp of the event at the requested index. If none,
198 * returns null.
199 *
200 * @param index the event index (rank)
201 * @return the corresponding event timestamp
202 */
203 public ITmfTimestamp getTimestamp(final int index) {
204 final ITmfContext context = seekEvent(index);
205 final ITmfEvent event = getNext(context);
206 return (event != null) ? event.getTimestamp() : null;
207 }
208
209 /**
210 * Set the file to be used for bookmarks on this experiment
211 *
212 * @param file the bookmarks file
213 */
214 public void setBookmarksFile(final IFile file) {
215 fBookmarksFile = file;
216 }
217
218 /**
219 * Get the file used for bookmarks on this experiment
220 *
221 * @return the bookmarks file or null if none is set
222 */
223 public IFile getBookmarksFile() {
224 return fBookmarksFile;
225 }
226
227 // ------------------------------------------------------------------------
228 // Request management
229 // ------------------------------------------------------------------------
230
231 @Override
232 protected ITmfContext armRequest(final ITmfDataRequest<T> request) {
233 if (request instanceof ITmfEventRequest<?>
234 && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest<T>) request).getRange().getStartTime())
235 && request.getIndex() == 0)
236 {
237 final ITmfContext context = seekEvent(((ITmfEventRequest<T>) request).getRange().getStartTime());
238 ((ITmfEventRequest<T>) request).setStartIndex((int) context.getRank());
239 return context;
240
241 }
242
243 // Check if we are already at the right index
244 if ((fExperimentContext != null) && fExperimentContext.getRank() == request.getIndex()) {
245 return fExperimentContext;
246 }
247
248 return seekEvent(request.getIndex());
249 }
250
251 // ------------------------------------------------------------------------
252 // ITmfTrace trace positioning
253 // ------------------------------------------------------------------------
254
255 /* (non-Javadoc)
256 *
257 * Returns a brand new context based on the location provided and
258 * initializes the event queues
259 *
260 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
261 */
262 @Override
263 public synchronized ITmfContext seekEvent(final ITmfLocation<?> location) {
264 // Validate the location
265 if (location != null && !(location instanceof TmfExperimentLocation)) {
266 return null; // Throw an exception?
267 }
268 // Make sure we have something to read from
269 if (fTraces == null) {
270 return null;
271 }
272
273 // Instantiate the location
274 final TmfExperimentLocation expLocation = (location == null)
275 ? new TmfExperimentLocation(new TmfLocationArray(new ITmfLocation<?>[fTraces.length]))
276 : (TmfExperimentLocation) location.clone();
277
278 // Create and populate the context's traces contexts
279 final TmfExperimentContext context = new TmfExperimentContext(new ITmfContext[fTraces.length]);
280
281 for (int i = 0; i < fTraces.length; i++) {
282 // Get the relevant trace attributes
283 final ITmfLocation<?> traceLocation = expLocation.getLocation().getLocations()[i];
284 context.getContexts()[i] = fTraces[i].seekEvent(traceLocation);
285 expLocation.getLocation().getLocations()[i] = context.getContexts()[i].getLocation().clone();
286 context.getEvents()[i] = fTraces[i].getNext(context.getContexts()[i]);
287 }
288
289 // Finalize context
290 context.setLocation(expLocation);
291 context.setLastTrace(TmfExperimentContext.NO_TRACE);
292 context.setRank(ITmfContext.UNKNOWN_RANK);
293
294 fExperimentContext = context;
295
296 return (ITmfContext) context;
297 }
298
299 /* (non-Javadoc)
300 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#seekEvent(double)
301 */
302 @Override
303 public ITmfContext seekEvent(final double ratio) {
304 final ITmfContext context = seekEvent((long) (ratio * getNbEvents()));
305 return context;
306 }
307
308 /* (non-Javadoc)
309 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getLocationRatio(org.eclipse.linuxtools.tmf.core.trace.ITmfLocation)
310 */
311 @Override
312 public double getLocationRatio(final ITmfLocation<?> location) {
313 if (location instanceof TmfExperimentLocation) {
314 return (double) seekEvent(location).getRank() / getNbEvents();
315 }
316 return 0.0;
317 }
318
319 /* (non-Javadoc)
320 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#getCurrentLocation()
321 */
322 @Override
323 public ITmfLocation<?> getCurrentLocation() {
324 ITmfLocation<?>[] locations = new ITmfLocation<?>[fTraces.length];
325 for (int i = 0; i < fTraces.length; i++) {
326 locations[i] = fTraces[i].getCurrentLocation();
327 }
328 return new TmfExperimentLocation(new TmfLocationArray(locations));
329 }
330
331 // ------------------------------------------------------------------------
332 // ITmfTrace trace positioning
333 // ------------------------------------------------------------------------
334
335 /* (non-Javadoc)
336 * @see org.eclipse.linuxtools.tmf.core.trace.TmfTrace#getNext(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
337 */
338 @Override
339 public synchronized T getNext(final ITmfContext context) {
340 final ITmfContext previousContext = (TmfExperimentContext) context.clone();
341 final T event = parseEvent(context);
342 if (event != null) {
343 updateAttributes(previousContext, event.getTimestamp());
344
345 fExperimentContext = (TmfExperimentContext) context;
346 int trace = fExperimentContext.getLastTrace();
347 if (trace != TmfExperimentContext.NO_TRACE) {
348 TmfExperimentLocation location = (TmfExperimentLocation) fExperimentContext.getLocation();
349 location.getLocation().getLocations()[trace] = fExperimentContext.getContexts()[trace].getLocation();
350 }
351
352 context.increaseRank();
353 processEvent(event);
354 }
355 return event;
356 }
357
358 /* (non-Javadoc)
359 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser#parseEvent(org.eclipse.linuxtools.tmf.core.trace.ITmfContext)
360 */
361 @SuppressWarnings("unchecked")
362 @Override
363 public T parseEvent(ITmfContext context) {
364
365 // Validate the context
366 if (!(context instanceof TmfExperimentContext)) {
367 return null; // Throw an exception?
368 }
369
370 TmfExperimentContext expContext = (TmfExperimentContext) context;
371
372 // If an event was consumed previously, first get the next one from that trace
373 final int lastTrace = expContext.getLastTrace();
374 if (lastTrace != TmfExperimentContext.NO_TRACE) {
375 final ITmfContext traceContext = expContext.getContexts()[lastTrace];
376 expContext.getEvents()[lastTrace] = fTraces[lastTrace].getNext(traceContext);
377 expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
378 }
379
380 // Scan the candidate events and identify the "next" trace to read from
381 int trace = TmfExperimentContext.NO_TRACE;
382 ITmfTimestamp timestamp = TmfTimestamp.BIG_CRUNCH;
383 for (int i = 0; i < fTraces.length; i++) {
384 final ITmfEvent event = expContext.getEvents()[i];
385 if (event != null && event.getTimestamp() != null) {
386 final ITmfTimestamp otherTS = event.getTimestamp();
387 if (otherTS.compareTo(timestamp, true) < 0) {
388 trace = i;
389 timestamp = otherTS;
390 }
391 }
392 }
393
394 T event = null;
395 if (trace != TmfExperimentContext.NO_TRACE) {
396 event = (T) expContext.getEvents()[trace];
397 }
398
399 expContext.setLastTrace(trace);
400 return event;
401 }
402
403 /* (non-Javadoc)
404 * @see java.lang.Object#toString()
405 */
406 @Override
407 @SuppressWarnings("nls")
408 public String toString() {
409 return "[TmfExperiment (" + getName() + ")]";
410 }
411
412 // ------------------------------------------------------------------------
413 // Streaming support
414 // ------------------------------------------------------------------------
415
416 private synchronized void initializeStreamingMonitor() {
417
418 if (fInitialized) {
419 return;
420 }
421 fInitialized = true;
422
423 if (getStreamingInterval() == 0) {
424 final ITmfContext context = seekEvent(0);
425 final ITmfEvent event = getNext(context);
426 if (event == null)
427 return;
428 final TmfTimeRange timeRange = new TmfTimeRange(event.getTimestamp().clone(), TmfTimestamp.BIG_CRUNCH);
429 final TmfExperimentRangeUpdatedSignal signal = new TmfExperimentRangeUpdatedSignal(this, this, timeRange);
430
431 // Broadcast in separate thread to prevent deadlock
432 new Thread() {
433 @Override
434 public void run() {
435 broadcast(signal);
436 }
437 }.start();
438 return;
439 }
440
441 final Thread thread = new Thread("Streaming Monitor for experiment " + getName()) { //$NON-NLS-1$
442 private ITmfTimestamp safeTimestamp = null;
443 private TmfTimeRange timeRange = null;
444
445 @Override
446 public void run() {
447 while (!fExecutor.isShutdown()) {
448 if (!getIndexer().isIndexing()) {
449 ITmfTimestamp startTimestamp = TmfTimestamp.BIG_CRUNCH;
450 ITmfTimestamp endTimestamp = TmfTimestamp.BIG_BANG;
451 for (final ITmfTrace<T> trace : fTraces) {
452 if (trace.getStartTime().compareTo(startTimestamp) < 0)
453 startTimestamp = trace.getStartTime();
454 if (trace.getStreamingInterval() != 0 && trace.getEndTime().compareTo(endTimestamp) > 0)
455 endTimestamp = trace.getEndTime();
456 }
457 if (safeTimestamp != null && safeTimestamp.compareTo(getTimeRange().getEndTime(), false) > 0)
458 timeRange = new TmfTimeRange(startTimestamp, safeTimestamp);
459 else
460 timeRange = null;
461 safeTimestamp = endTimestamp;
462 if (timeRange != null) {
463 final TmfExperimentRangeUpdatedSignal signal =
464 new TmfExperimentRangeUpdatedSignal(TmfExperiment.this, TmfExperiment.this, timeRange);
465 broadcast(signal);
466 }
467 }
468 try {
469 Thread.sleep(getStreamingInterval());
470 } catch (final InterruptedException e) {
471 e.printStackTrace();
472 }
473 }
474 }
475 };
476 thread.start();
477 }
478
479 /* (non-Javadoc)
480 * @see org.eclipse.linuxtools.tmf.trace.ITmfTrace#getStreamingInterval()
481 */
482 @Override
483 public long getStreamingInterval() {
484 long interval = 0;
485 for (final ITmfTrace<T> trace : fTraces)
486 interval = Math.max(interval, trace.getStreamingInterval());
487 return interval;
488 }
489
490 // ------------------------------------------------------------------------
491 // Signal handlers
492 // ------------------------------------------------------------------------
493
494 private Integer fEndSynchReference;
495
496 /**
497 * Signal handler for the TmfExperimentSelectedSignal signal
498 *
499 * @param signal
500 */
501 @TmfSignalHandler
502 public void experimentSelected(final TmfExperimentSelectedSignal<T> signal) {
503 final TmfExperiment<?> experiment = signal.getExperiment();
504 if (experiment == this) {
505 setCurrentExperiment(experiment);
506 fEndSynchReference = Integer.valueOf(signal.getReference());
507 }
508 }
509
510 /**
511 * Signal handler for the TmfEndSynchSignal signal
512 *
513 * @param signal
514 */
515 @TmfSignalHandler
516 public void endSync(final TmfEndSynchSignal signal) {
517 if (fEndSynchReference != null && fEndSynchReference.intValue() == signal.getReference()) {
518 fEndSynchReference = null;
519 initializeStreamingMonitor();
520 }
521 }
522
523 /**
524 * Signal handler for the TmfTraceUpdatedSignal signal
525 *
526 * @param signal
527 */
528 @TmfSignalHandler
529 public void traceUpdated(final TmfTraceUpdatedSignal signal) {
530 if (signal.getTrace() == this) {
531 broadcast(new TmfExperimentUpdatedSignal(this, this));
532 }
533 }
534
535 /**
536 * Signal handler for the TmfExperimentRangeUpdatedSignal signal
537 *
538 * @param signal
539 */
540 @TmfSignalHandler
541 public void experimentRangeUpdated(final TmfExperimentRangeUpdatedSignal signal) {
542 if (signal.getExperiment() == this) {
543 getIndexer().buildIndex(getNbEvents(), signal.getRange(), false);
544 }
545 }
546
547 }
This page took 0.04208 seconds and 5 git commands to generate.