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