lttng: Support for existing live sessions
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / statesystem / TmfStateSystemAnalysisModule.java
CommitLineData
8a6ff07f 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2013, 2014 École Polytechnique de Montréal
8a6ff07f
GB
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 * Geneviève Bastien - Initial API and implementation
baa96b1d 11 * Bernd Hufmann - Integrated history builder functionality
8a6ff07f
GB
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.tmf.core.statesystem;
8a6ff07f
GB
15
16import java.io.File;
baa96b1d 17import java.io.IOException;
5237a931 18import java.util.Collections;
09ec275e 19import java.util.concurrent.CountDownLatch;
8a6ff07f
GB
20
21import org.eclipse.core.runtime.IProgressMonitor;
e1c415b3 22import org.eclipse.core.runtime.IStatus;
baa96b1d 23import org.eclipse.core.runtime.NullProgressMonitor;
8a6ff07f 24import org.eclipse.jdt.annotation.NonNull;
baa96b1d
BH
25import org.eclipse.jdt.annotation.NonNullByDefault;
26import org.eclipse.jdt.annotation.Nullable;
2bdf0193
AM
27import org.eclipse.tracecompass.internal.tmf.core.statesystem.backends.partial.PartialHistoryBackend;
28import org.eclipse.tracecompass.internal.tmf.core.statesystem.backends.partial.PartialStateSystem;
e894a508
AM
29import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
30import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
31import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
32import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
33import org.eclipse.tracecompass.statesystem.core.backend.InMemoryBackend;
34import org.eclipse.tracecompass.statesystem.core.backend.NullBackend;
35import org.eclipse.tracecompass.statesystem.core.backend.historytree.HistoryTreeBackend;
36import org.eclipse.tracecompass.statesystem.core.backend.historytree.ThreadedHistoryTreeBackend;
2bdf0193
AM
37import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
38import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
39import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
40import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
41import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
42import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
43import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
44import org.eclipse.tracecompass.tmf.core.trace.TmfExperiment;
45import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
8a6ff07f
GB
46
47/**
48 * Abstract analysis module to generate a state system. It is a base class that
49 * can be used as a shortcut by analysis who just need to build a single state
50 * system with a state provider.
51 *
52 * Analysis implementing this class should only need to provide a state system
53 * and optionally a backend (default to NULL) and, if required, a filename
54 * (defaults to the analysis'ID)
55 *
56 * @author Geneviève Bastien
57 * @since 3.0
58 */
baa96b1d 59@NonNullByDefault
8a6ff07f 60public abstract class TmfStateSystemAnalysisModule extends TmfAbstractAnalysisModule
5237a931 61 implements ITmfAnalysisModuleWithStateSystems {
8a6ff07f 62
8a6ff07f
GB
63 private static final String EXTENSION = ".ht"; //$NON-NLS-1$
64
09ec275e
AM
65 private final CountDownLatch fInitialized = new CountDownLatch(1);
66
baa96b1d
BH
67 @Nullable private ITmfStateSystemBuilder fStateSystem;
68 @Nullable private ITmfStateProvider fStateProvider;
69 @Nullable private IStateHistoryBackend fHtBackend;
70 @Nullable private ITmfEventRequest fRequest;
5237a931 71
8a6ff07f
GB
72 /**
73 * State system backend types
74 *
75 * @author Geneviève Bastien
76 */
77 protected enum StateSystemBackendType {
78 /** Full history in file */
79 FULL,
80 /** In memory state system */
81 INMEM,
82 /** Null history */
83 NULL,
84 /** State system backed with partial history */
85 PARTIAL
86 }
87
72221aa4
AM
88
89 /**
90 * Retrieve a state system belonging to trace, by passing the ID of the
91 * relevant analysis module.
92 *
93 * This will start the execution of the analysis module, and start the
94 * construction of the state system, if needed.
95 *
96 * @param trace
97 * The trace for which you want the state system
98 * @param moduleId
99 * The ID of the state system analysis module
100 * @return The state system, or null if there was no match
101 * @since 3.1
102 */
103 public static @Nullable ITmfStateSystem getStateSystem(ITmfTrace trace, String moduleId) {
104 TmfStateSystemAnalysisModule module =
105 trace.getAnalysisModuleOfClass(TmfStateSystemAnalysisModule.class, moduleId);
106 if (module != null) {
e1c415b3
BH
107 IStatus status = module.schedule();
108 if (status.isOK()) {
109 module.waitForInitialization();
e1c415b3
BH
110 return module.getStateSystem();
111 }
72221aa4
AM
112 }
113 return null;
114 }
115
8a6ff07f
GB
116 /**
117 * Get the state provider for this analysis module
118 *
119 * @return the state provider
120 */
8a6ff07f
GB
121 protected abstract ITmfStateProvider createStateProvider();
122
123 /**
124 * Get the state system backend type used by this module
125 *
126 * @return The {@link StateSystemBackendType}
127 */
a3b864c0
AM
128 protected StateSystemBackendType getBackendType() {
129 /* Using full history by default, sub-classes can override */
130 return StateSystemBackendType.FULL;
131 }
8a6ff07f
GB
132
133 /**
134 * Get the supplementary file name where to save this state system. The
135 * default is the ID of the analysis followed by the extension.
136 *
137 * @return The supplementary file name
138 */
139 protected String getSsFileName() {
140 return getId() + EXTENSION;
141 }
142
143 /**
baa96b1d
BH
144 * Get the state system generated by this analysis, or null if it is not yet
145 * created.
8a6ff07f
GB
146 *
147 * @return The state system
148 */
baa96b1d 149 @Nullable
8a6ff07f
GB
150 public ITmfStateSystem getStateSystem() {
151 return fStateSystem;
152 }
153
09ec275e
AM
154 /**
155 * Block the calling thread until the analysis module has been initialized.
156 * After this method returns, {@link #getStateSystem()} should not return
157 * null anymore.
158 */
159 public void waitForInitialization() {
160 try {
161 fInitialized.await();
162 } catch (InterruptedException e) {}
163 }
164
baa96b1d
BH
165 // ------------------------------------------------------------------------
166 // TmfAbstractAnalysisModule
167 // ------------------------------------------------------------------------
8a6ff07f 168
baa96b1d
BH
169 @Override
170 protected boolean executeAnalysis(@Nullable final IProgressMonitor monitor) {
171 IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
172 final ITmfStateProvider provider = createStateProvider();
8a6ff07f 173
84a9548a 174 String id = getId();
84a9548a 175
8a6ff07f
GB
176 /* FIXME: State systems should make use of the monitor, to be cancelled */
177 try {
178 /* Get the state system according to backend */
179 StateSystemBackendType backend = getBackendType();
180 String directory;
baa96b1d 181 File htFile;
e1c415b3
BH
182
183 ITmfTrace trace = getTrace();
184 if (trace == null) {
185 // Analysis was cancelled in the meantime
186 fInitialized.countDown();
187 return false;
188 }
8a6ff07f
GB
189 switch (backend) {
190 case FULL:
e1c415b3 191 directory = TmfTraceManager.getSupplementaryFileDir(trace);
baa96b1d 192 htFile = new File(directory + getSsFileName());
84a9548a 193 createFullHistory(id, provider, htFile);
8a6ff07f
GB
194 break;
195 case PARTIAL:
e1c415b3 196 directory = TmfTraceManager.getSupplementaryFileDir(trace);
baa96b1d 197 htFile = new File(directory + getSsFileName());
84a9548a 198 createPartialHistory(id, provider, htFile);
8a6ff07f
GB
199 break;
200 case INMEM:
84a9548a 201 createInMemoryHistory(id, provider);
8a6ff07f
GB
202 break;
203 case NULL:
84a9548a 204 createNullHistory(id, provider);
8a6ff07f
GB
205 break;
206 default:
207 break;
208 }
209 } catch (TmfTraceException e) {
e1c415b3 210 fInitialized.countDown();
8a6ff07f
GB
211 return false;
212 }
baa96b1d 213 return !mon.isCanceled();
8a6ff07f
GB
214 }
215
216 @Override
217 protected void canceling() {
baa96b1d
BH
218 ITmfEventRequest req = fRequest;
219 if ((req != null) && (!req.isCompleted())) {
220 req.cancel();
221 }
222 }
223
a1529f38
AM
224 @Override
225 public void dispose() {
130e6f4e 226 super.dispose();
a1529f38
AM
227 if (fStateSystem != null) {
228 fStateSystem.dispose();
229 }
a1529f38
AM
230 }
231
baa96b1d
BH
232 // ------------------------------------------------------------------------
233 // History creation methods
234 // ------------------------------------------------------------------------
235
236 /*
237 * Load the history file matching the target trace. If the file already
238 * exists, it will be opened directly. If not, it will be created from
239 * scratch.
240 */
84a9548a 241 private void createFullHistory(String id, ITmfStateProvider provider, File htFile) throws TmfTraceException {
baa96b1d
BH
242
243 /* If the target file already exists, do not rebuild it uselessly */
244 // TODO for now we assume it's complete. Might be a good idea to check
245 // at least if its range matches the trace's range.
246
247 if (htFile.exists()) {
248 /* Load an existing history */
249 final int version = provider.getVersion();
250 try {
84a9548a
AM
251 IStateHistoryBackend backend = new HistoryTreeBackend(htFile, version);
252 fHtBackend = backend;
bcec0116 253 fStateSystem = StateSystemFactory.newStateSystem(id, backend, false);
09ec275e 254 fInitialized.countDown();
baa96b1d
BH
255 return;
256 } catch (IOException e) {
257 /*
258 * There was an error opening the existing file. Perhaps it was
259 * corrupted, perhaps it's an old version? We'll just
260 * fall-through and try to build a new one from scratch instead.
261 */
262 }
263 }
264
265 /* Size of the blocking queue to use when building a state history */
266 final int QUEUE_SIZE = 10000;
267
268 try {
84a9548a 269 IStateHistoryBackend backend = new ThreadedHistoryTreeBackend(htFile,
baa96b1d 270 provider.getStartTime(), provider.getVersion(), QUEUE_SIZE);
84a9548a 271 fHtBackend = backend;
bcec0116 272 fStateSystem = StateSystemFactory.newStateSystem(id, backend);
baa96b1d
BH
273 provider.assignTargetStateSystem(fStateSystem);
274 build(provider);
275 } catch (IOException e) {
276 /*
277 * If it fails here however, it means there was a problem writing to
278 * the disk, so throw a real exception this time.
279 */
280 throw new TmfTraceException(e.toString(), e);
281 }
282 }
283
284 /*
285 * Create a new state system backed with a partial history. A partial
286 * history is similar to a "full" one (which you get with
287 * {@link #newFullHistory}), except that the file on disk is much smaller,
288 * but queries are a bit slower.
289 *
290 * Also note that single-queries are implemented using a full-query
291 * underneath, (which are much slower), so this might not be a good fit for
292 * a use case where you have to do lots of single queries.
293 */
84a9548a 294 private void createPartialHistory(String id, ITmfStateProvider provider, File htPartialFile)
baa96b1d
BH
295 throws TmfTraceException {
296 /*
297 * The order of initializations is very tricky (but very important!)
298 * here. We need to follow this pattern:
299 * (1 is done before the call to this method)
300 *
301 * 1- Instantiate realStateProvider
302 * 2- Instantiate realBackend
303 * 3- Instantiate partialBackend, with prereqs:
304 * 3a- Instantiate partialProvider, via realProvider.getNew()
305 * 3b- Instantiate nullBackend (partialSS's backend)
306 * 3c- Instantiate partialSS
307 * 3d- partialProvider.assignSS(partialSS)
308 * 4- Instantiate realSS
309 * 5- partialSS.assignUpstream(realSS)
310 * 6- realProvider.assignSS(realSS)
311 * 7- Call HistoryBuilder(realProvider, realSS, partialBackend) to build the thing.
312 */
313
314 /* Size of the blocking queue to use when building a state history */
315 final int QUEUE_SIZE = 10000;
316
317 final long granularity = 50000;
318
319 /* 2 */
320 IStateHistoryBackend realBackend = null;
321 try {
322 realBackend = new ThreadedHistoryTreeBackend(htPartialFile,
323 provider.getStartTime(), provider.getVersion(), QUEUE_SIZE);
324 } catch (IOException e) {
325 throw new TmfTraceException(e.toString(), e);
326 }
327
328 /* 3a */
329 ITmfStateProvider partialProvider = provider.getNewInstance();
330
331 /* 3b-3c, constructor automatically uses a NullBackend */
332 PartialStateSystem pss = new PartialStateSystem();
333
334 /* 3d */
335 partialProvider.assignTargetStateSystem(pss);
336
337 /* 3 */
338 IStateHistoryBackend partialBackend =
339 new PartialHistoryBackend(partialProvider, pss, realBackend, granularity);
340
341 /* 4 */
bcec0116 342 @SuppressWarnings("restriction")
e894a508
AM
343 org.eclipse.tracecompass.internal.statesystem.core.StateSystem realSS =
344 (org.eclipse.tracecompass.internal.statesystem.core.StateSystem) StateSystemFactory.newStateSystem(id, partialBackend);
baa96b1d
BH
345
346 /* 5 */
347 pss.assignUpstream(realSS);
348
349 /* 6 */
350 provider.assignTargetStateSystem(realSS);
351
352 /* 7 */
353 fHtBackend = partialBackend;
354 fStateSystem = realSS;
355
356 build(provider);
357 }
358
359 /*
360 * Create a new state system using a null history back-end. This means that
361 * no history intervals will be saved anywhere, and as such only
362 * {@link ITmfStateSystem#queryOngoingState} will be available.
363 */
84a9548a
AM
364 private void createNullHistory(String id, ITmfStateProvider provider) {
365 IStateHistoryBackend backend = new NullBackend();
366 fHtBackend = backend;
bcec0116 367 fStateSystem = StateSystemFactory.newStateSystem(id, backend);
baa96b1d
BH
368 provider.assignTargetStateSystem(fStateSystem);
369 build(provider);
370 }
371
372 /*
373 * Create a new state system using in-memory interval storage. This should
374 * only be done for very small state system, and will be naturally limited
375 * to 2^31 intervals.
376 */
84a9548a
AM
377 private void createInMemoryHistory(String id, ITmfStateProvider provider) {
378 IStateHistoryBackend backend = new InMemoryBackend(provider.getStartTime());
379 fHtBackend = backend;
bcec0116 380 fStateSystem = StateSystemFactory.newStateSystem(id, backend);
baa96b1d
BH
381 provider.assignTargetStateSystem(fStateSystem);
382 build(provider);
383 }
384
a1529f38 385 private void disposeProvider(boolean deleteFiles) {
baa96b1d
BH
386 ITmfStateProvider provider = fStateProvider;
387 if (provider != null) {
388 provider.dispose();
389 }
390 if (deleteFiles && (fHtBackend != null)) {
391 fHtBackend.removeFiles();
392 }
393 }
394
395 private void build(ITmfStateProvider provider) {
396 if ((fStateSystem == null) || (fHtBackend == null)) {
397 throw new IllegalArgumentException();
398 }
399
400 ITmfEventRequest request = fRequest;
401 if ((request != null) && (!request.isCompleted())) {
402 request.cancel();
403 }
404
405 request = new StateSystemEventRequest(provider);
406 provider.getTrace().sendRequest(request);
407
8a6ff07f 408 /*
baa96b1d
BH
409 * Only now that we've actually started the build, we'll update the
410 * class fields, so that they become visible for other callers.
8a6ff07f 411 */
baa96b1d
BH
412 fStateProvider = provider;
413 fRequest = request;
414
09ec275e
AM
415 /*
416 * The state system object is now created, we can consider this module
417 * "initialized" (components can retrieve it and start doing queries).
418 */
419 fInitialized.countDown();
420
421 /*
422 * Block the executeAnalysis() construction is complete (so that the
423 * progress monitor displays that it is running).
424 */
baa96b1d 425 try {
09ec275e 426 request.waitForCompletion();
baa96b1d
BH
427 } catch (InterruptedException e) {
428 e.printStackTrace();
429 }
430 }
431
432 private class StateSystemEventRequest extends TmfEventRequest {
433 private final ITmfStateProvider sci;
434 private final ITmfTrace trace;
435
436 public StateSystemEventRequest(ITmfStateProvider sp) {
437 super(sp.getExpectedEventType(),
438 TmfTimeRange.ETERNITY,
439 0,
440 ITmfEventRequest.ALL_DATA,
441 ITmfEventRequest.ExecutionType.BACKGROUND);
442 this.sci = sp;
443
444 // sci.getTrace() will eventually return a @NonNull
445 @SuppressWarnings("null")
446 @NonNull ITmfTrace tr = sci.getTrace();
2d208fb7 447 trace = tr;
baa96b1d 448
baa96b1d
BH
449 }
450
451 @Override
41f3b36b 452 public void handleData(final ITmfEvent event) {
baa96b1d 453 super.handleData(event);
41f3b36b 454 if (event.getTrace() == trace) {
baa96b1d 455 sci.processEvent(event);
2d208fb7
GB
456 } else if (trace instanceof TmfExperiment) {
457 /*
458 * If the request is for an experiment, check if the event is
459 * from one of the child trace
460 */
461 for (ITmfTrace childTrace : ((TmfExperiment) trace).getTraces()) {
462 if (childTrace == event.getTrace()) {
463 sci.processEvent(event);
464 }
465 }
baa96b1d
BH
466 }
467 }
468
469 @Override
470 public void handleSuccess() {
471 super.handleSuccess();
a1529f38 472 disposeProvider(false);
baa96b1d
BH
473 }
474
475 @Override
476 public void handleCancel() {
477 super.handleCancel();
a1529f38 478 disposeProvider(true);
baa96b1d
BH
479 }
480
481 @Override
482 public void handleFailure() {
483 super.handleFailure();
a1529f38 484 disposeProvider(true);
baa96b1d 485 }
8a6ff07f
GB
486 }
487
5237a931
AM
488 // ------------------------------------------------------------------------
489 // ITmfAnalysisModuleWithStateSystems
490 // ------------------------------------------------------------------------
491
492 @Override
baa96b1d
BH
493 @Nullable
494 public ITmfStateSystem getStateSystem(String id) {
5237a931
AM
495 if (id.equals(getId())) {
496 return fStateSystem;
497 }
498 return null;
499 }
500
8a6ff07f 501 @Override
5237a931 502 public Iterable<ITmfStateSystem> getStateSystems() {
baa96b1d
BH
503 @SuppressWarnings("null")
504 @NonNull Iterable<ITmfStateSystem> ret = Collections.singleton((ITmfStateSystem) fStateSystem);
505 return ret;
8a6ff07f
GB
506 }
507}
This page took 0.065423 seconds and 5 git commands to generate.