tmf: Update CTF and custom trace validation
[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 59 private static final String EXTENSION = ".ht"; //$NON-NLS-1$
84a9548a 60 private static final String UNDEFINED_ID = "undefined"; //$NON-NLS-1$
8a6ff07f 61
09ec275e
AM
62 private final CountDownLatch fInitialized = new CountDownLatch(1);
63
baa96b1d
BH
64 @Nullable private ITmfStateSystemBuilder fStateSystem;
65 @Nullable private ITmfStateProvider fStateProvider;
66 @Nullable private IStateHistoryBackend fHtBackend;
67 @Nullable private ITmfEventRequest fRequest;
5237a931 68
8a6ff07f
GB
69 /**
70 * State system backend types
71 *
72 * @author Geneviève Bastien
73 */
74 protected enum StateSystemBackendType {
75 /** Full history in file */
76 FULL,
77 /** In memory state system */
78 INMEM,
79 /** Null history */
80 NULL,
81 /** State system backed with partial history */
82 PARTIAL
83 }
84
85 /**
86 * Get the state provider for this analysis module
87 *
88 * @return the state provider
89 */
8a6ff07f
GB
90 protected abstract ITmfStateProvider createStateProvider();
91
92 /**
93 * Get the state system backend type used by this module
94 *
95 * @return The {@link StateSystemBackendType}
96 */
97 protected abstract StateSystemBackendType getBackendType();
98
99 /**
100 * Get the supplementary file name where to save this state system. The
101 * default is the ID of the analysis followed by the extension.
102 *
103 * @return The supplementary file name
104 */
105 protected String getSsFileName() {
106 return getId() + EXTENSION;
107 }
108
109 /**
baa96b1d
BH
110 * Get the state system generated by this analysis, or null if it is not yet
111 * created.
8a6ff07f
GB
112 *
113 * @return The state system
114 */
baa96b1d 115 @Nullable
8a6ff07f
GB
116 public ITmfStateSystem getStateSystem() {
117 return fStateSystem;
118 }
119
09ec275e
AM
120 /**
121 * Block the calling thread until the analysis module has been initialized.
122 * After this method returns, {@link #getStateSystem()} should not return
123 * null anymore.
124 */
125 public void waitForInitialization() {
126 try {
127 fInitialized.await();
128 } catch (InterruptedException e) {}
129 }
130
baa96b1d
BH
131 // ------------------------------------------------------------------------
132 // TmfAbstractAnalysisModule
133 // ------------------------------------------------------------------------
8a6ff07f 134
baa96b1d
BH
135 @Override
136 protected boolean executeAnalysis(@Nullable final IProgressMonitor monitor) {
137 IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
138 final ITmfStateProvider provider = createStateProvider();
8a6ff07f 139
84a9548a
AM
140 String id = getId();
141 if (id == null) {
142 /* The analysis module does not specify an ID, use a generic one */
143 id = UNDEFINED_ID;
144 }
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() {
188 if (fStateSystem != null) {
189 fStateSystem.dispose();
190 }
191 super.dispose();
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;
215 fStateSystem = new StateSystem(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
AM
233 fHtBackend = backend;
234 fStateSystem = new StateSystem(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 */
84a9548a 304 StateSystem realSS = new StateSystem(id, partialBackend);
baa96b1d
BH
305
306 /* 5 */
307 pss.assignUpstream(realSS);
308
309 /* 6 */
310 provider.assignTargetStateSystem(realSS);
311
312 /* 7 */
313 fHtBackend = partialBackend;
314 fStateSystem = realSS;
315
316 build(provider);
317 }
318
319 /*
320 * Create a new state system using a null history back-end. This means that
321 * no history intervals will be saved anywhere, and as such only
322 * {@link ITmfStateSystem#queryOngoingState} will be available.
323 */
84a9548a
AM
324 private void createNullHistory(String id, ITmfStateProvider provider) {
325 IStateHistoryBackend backend = new NullBackend();
326 fHtBackend = backend;
327 fStateSystem = new StateSystem(id, backend);
baa96b1d
BH
328 provider.assignTargetStateSystem(fStateSystem);
329 build(provider);
330 }
331
332 /*
333 * Create a new state system using in-memory interval storage. This should
334 * only be done for very small state system, and will be naturally limited
335 * to 2^31 intervals.
336 */
84a9548a
AM
337 private void createInMemoryHistory(String id, ITmfStateProvider provider) {
338 IStateHistoryBackend backend = new InMemoryBackend(provider.getStartTime());
339 fHtBackend = backend;
340 fStateSystem = new StateSystem(id, backend);
baa96b1d
BH
341 provider.assignTargetStateSystem(fStateSystem);
342 build(provider);
343 }
344
a1529f38 345 private void disposeProvider(boolean deleteFiles) {
baa96b1d
BH
346 ITmfStateProvider provider = fStateProvider;
347 if (provider != null) {
348 provider.dispose();
349 }
350 if (deleteFiles && (fHtBackend != null)) {
351 fHtBackend.removeFiles();
352 }
353 }
354
355 private void build(ITmfStateProvider provider) {
356 if ((fStateSystem == null) || (fHtBackend == null)) {
357 throw new IllegalArgumentException();
358 }
359
360 ITmfEventRequest request = fRequest;
361 if ((request != null) && (!request.isCompleted())) {
362 request.cancel();
363 }
364
365 request = new StateSystemEventRequest(provider);
366 provider.getTrace().sendRequest(request);
367
8a6ff07f 368 /*
baa96b1d
BH
369 * Only now that we've actually started the build, we'll update the
370 * class fields, so that they become visible for other callers.
8a6ff07f 371 */
baa96b1d
BH
372 fStateProvider = provider;
373 fRequest = request;
374
09ec275e
AM
375 /*
376 * The state system object is now created, we can consider this module
377 * "initialized" (components can retrieve it and start doing queries).
378 */
379 fInitialized.countDown();
380
381 /*
382 * Block the executeAnalysis() construction is complete (so that the
383 * progress monitor displays that it is running).
384 */
baa96b1d 385 try {
09ec275e 386 request.waitForCompletion();
baa96b1d
BH
387 } catch (InterruptedException e) {
388 e.printStackTrace();
389 }
390 }
391
392 private class StateSystemEventRequest extends TmfEventRequest {
393 private final ITmfStateProvider sci;
394 private final ITmfTrace trace;
395
396 public StateSystemEventRequest(ITmfStateProvider sp) {
397 super(sp.getExpectedEventType(),
398 TmfTimeRange.ETERNITY,
399 0,
400 ITmfEventRequest.ALL_DATA,
401 ITmfEventRequest.ExecutionType.BACKGROUND);
402 this.sci = sp;
403
404 // sci.getTrace() will eventually return a @NonNull
405 @SuppressWarnings("null")
406 @NonNull ITmfTrace tr = sci.getTrace();
407
408 this.trace = tr;
409 }
410
411 @Override
412 public void handleData(final @Nullable ITmfEvent event) {
413 super.handleData(event);
414 if (event != null && event.getTrace() == trace) {
415 sci.processEvent(event);
416 }
417 }
418
419 @Override
420 public void handleSuccess() {
421 super.handleSuccess();
a1529f38 422 disposeProvider(false);
baa96b1d
BH
423 }
424
425 @Override
426 public void handleCancel() {
427 super.handleCancel();
a1529f38 428 disposeProvider(true);
baa96b1d
BH
429 }
430
431 @Override
432 public void handleFailure() {
433 super.handleFailure();
a1529f38 434 disposeProvider(true);
baa96b1d 435 }
8a6ff07f
GB
436 }
437
5237a931
AM
438 // ------------------------------------------------------------------------
439 // ITmfAnalysisModuleWithStateSystems
440 // ------------------------------------------------------------------------
441
442 @Override
baa96b1d
BH
443 @Nullable
444 public ITmfStateSystem getStateSystem(String id) {
5237a931
AM
445 if (id.equals(getId())) {
446 return fStateSystem;
447 }
448 return null;
449 }
450
451 @Override
baa96b1d
BH
452 @Nullable
453 public String getStateSystemId(ITmfStateSystem ss) {
5237a931
AM
454 return getId();
455 }
456
8a6ff07f 457 @Override
5237a931 458 public Iterable<ITmfStateSystem> getStateSystems() {
baa96b1d
BH
459 @SuppressWarnings("null")
460 @NonNull Iterable<ITmfStateSystem> ret = Collections.singleton((ITmfStateSystem) fStateSystem);
461 return ret;
8a6ff07f
GB
462 }
463}
This page took 0.049102 seconds and 5 git commands to generate.