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