tmf: Fold IStateSystemQuerier2 back into IStateSystemQuerier
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / StateSystem.java
CommitLineData
a52fde77
AM
1/*******************************************************************************
2 * Copyright (c) 2012 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5df842b3 5 *
a52fde77
AM
6 * All rights reserved. This program and the accompanying materials are
7 * made available under the terms of the Eclipse Public License v1.0 which
8 * accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
5df842b3 10 *
a52fde77
AM
11 *******************************************************************************/
12
18ab1d18 13package org.eclipse.linuxtools.internal.tmf.core.statesystem;
a52fde77 14
8d1346f0
AM
15import java.io.File;
16import java.io.IOException;
a52fde77 17import java.io.PrintWriter;
8d1346f0 18import java.util.ArrayList;
f94a0bac 19import java.util.LinkedList;
a52fde77
AM
20import java.util.List;
21
8d1346f0
AM
22import org.eclipse.core.runtime.IProgressMonitor;
23import org.eclipse.core.runtime.NullProgressMonitor;
24import org.eclipse.linuxtools.internal.tmf.core.Tracer;
6d08acca
AM
25import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
26import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
27import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
8d1346f0
AM
28import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
29import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
30import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemBuilder;
a52fde77 31import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
a52fde77
AM
32import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
33
34/**
8d1346f0
AM
35 * This is the core class of the Generic State System. It contains all the
36 * methods to build and query a state history. It's exposed externally through
37 * the IStateSystemQuerier and IStateSystemBuilder interfaces, depending if the
38 * user needs read-only access or read-write access.
5df842b3 39 *
8d1346f0
AM
40 * When building, DON'T FORGET to call .closeHistory() when you are done
41 * inserting intervals, or the storage backend will have no way of knowing it
42 * can close and write itself to disk, and its thread will keep running.
5df842b3 43 *
a52fde77 44 * @author alexmont
5df842b3 45 *
a52fde77 46 */
b5a8d0cc 47public class StateSystem implements IStateSystemBuilder {
a52fde77
AM
48
49 /* References to the inner structures */
8d1346f0
AM
50 private final AttributeTree attributeTree;
51 private final TransientState transState;
52 private final IStateHistoryBackend backend;
a52fde77
AM
53
54 /**
8d1346f0
AM
55 * General constructor
56 *
57 * @param backend
58 * The "state history storage" backend to use.
59 * @param newFile
60 * Put true if this is a new history started from scratch. It is
61 * used to tell the state system where to get its attribute tree.
62 * @throws IOException
63 * If there was a problem creating the new history file
a52fde77 64 */
8d1346f0
AM
65 public StateSystem(IStateHistoryBackend backend, boolean newFile)
66 throws IOException {
67 this.backend = backend;
68 this.transState = new TransientState(backend);
a52fde77 69
8d1346f0
AM
70 if (newFile) {
71 attributeTree = new AttributeTree(this);
72 } else {
73 /* We're opening an existing file */
74 this.attributeTree = new AttributeTree(this, backend.supplyAttributeTreeReader());
75 transState.setInactive();
76 }
a52fde77
AM
77 }
78
8d1346f0
AM
79 //--------------------------------------------------------------------------
80 // General methods related to the attribute tree
81 //--------------------------------------------------------------------------
82
83 /**
84 * Method used by the attribute tree when creating new attributes, to keep
85 * the attribute count in the transient state in sync.
86 */
87 void addEmptyAttribute() {
88 transState.addEmptyEntry();
89 }
90
91 @Override
4623f57f
AM
92 public int getNbAttributes() {
93 return attributeTree.getNbAttributes();
94 }
95
8d1346f0
AM
96 @Override
97 public String getAttributeName(int attributeQuark) {
98 return attributeTree.getAttributeName(attributeQuark);
99 }
100
101 @Override
102 public String getFullAttributePath(int attributeQuark) {
103 return attributeTree.getFullAttributeName(attributeQuark);
104 }
105
106 //--------------------------------------------------------------------------
107 // Methods related to the storage backend
108 //--------------------------------------------------------------------------
a52fde77 109
8d1346f0
AM
110 @Override
111 public long getStartTime() {
112 return backend.getStartTime();
113 }
114
115 @Override
116 public long getCurrentEndTime() {
117 return backend.getEndTime();
118 }
119
120 @Override
121 public void closeHistory(long endTime) throws TimeRangeException {
122 File attributeTreeFile;
123 long attributeTreeFilePos;
124 long realEndTime = endTime;
125
126 if (realEndTime < backend.getEndTime()) {
127 /*
128 * This can happen (empty nodes pushing the border further, etc.)
129 * but shouldn't be too big of a deal.
130 */
131 realEndTime = backend.getEndTime();
132 }
133 transState.closeTransientState(realEndTime);
134 backend.finishedBuilding(realEndTime);
135
136 attributeTreeFile = backend.supplyAttributeTreeWriterFile();
137 attributeTreeFilePos = backend.supplyAttributeTreeWriterFilePosition();
138 if (attributeTreeFile != null) {
139 /*
140 * If null was returned, we simply won't save the attribute tree,
141 * too bad!
142 */
143 attributeTree.writeSelf(attributeTreeFile, attributeTreeFilePos);
144 }
145 }
146
147 //--------------------------------------------------------------------------
148 // Quark-retrieving methods
149 //--------------------------------------------------------------------------
150
151 @Override
a52fde77
AM
152 public int getQuarkAbsolute(String... attribute)
153 throws AttributeNotFoundException {
154 return attributeTree.getQuarkDontAdd(-1, attribute);
155 }
156
8d1346f0 157 @Override
a52fde77
AM
158 public int getQuarkAbsoluteAndAdd(String... attribute) {
159 return attributeTree.getQuarkAndAdd(-1, attribute);
160 }
161
8d1346f0 162 @Override
a52fde77
AM
163 public int getQuarkRelative(int startingNodeQuark, String... subPath)
164 throws AttributeNotFoundException {
165 return attributeTree.getQuarkDontAdd(startingNodeQuark, subPath);
166 }
167
8d1346f0 168 @Override
a52fde77
AM
169 public int getQuarkRelativeAndAdd(int startingNodeQuark, String... subPath) {
170 return attributeTree.getQuarkAndAdd(startingNodeQuark, subPath);
171 }
172
8d1346f0 173 @Override
c66426fd 174 public List<Integer> getSubAttributes(int quark, boolean recursive)
0a9de3d2 175 throws AttributeNotFoundException {
c66426fd 176 return attributeTree.getSubAttributes(quark, recursive);
0a9de3d2
AM
177 }
178
8d1346f0 179 @Override
f94a0bac
AM
180 public List<Integer> getQuarks(String... pattern) {
181 List<Integer> quarks = new LinkedList<Integer>();
182 List<String> prefix = new LinkedList<String>();
183 List<String> suffix = new LinkedList<String>();
184 boolean split = false;
185 String[] prefixStr;
186 String[] suffixStr;
187 List<Integer> directChildren;
188 int startingAttribute;
189
190 /* Fill the "prefix" and "suffix" parts of the pattern around the '*' */
191 for (String entry : pattern) {
192 if (entry.equals("*")) { //$NON-NLS-1$
193 if (split) {
194 /*
195 * Split was already true? This means there was more than
196 * one wildcard. This is not supported, return an empty
197 * list.
198 */
199 return quarks;
200 }
201 split = true;
202 continue;
203 }
204
205 if (split) {
206 suffix.add(entry);
207 } else {
208 prefix.add(entry);
209 }
210 }
211 prefixStr = prefix.toArray(new String[prefix.size()]);
212 suffixStr = suffix.toArray(new String[suffix.size()]);
213
214 /*
215 * If there was no wildcard, we'll only return the one matching
216 * attribute, if there is one.
217 */
218 if (split == false) {
219 int quark;
220 try {
221 quark = getQuarkAbsolute(prefixStr);
222 } catch (AttributeNotFoundException e) {
223 /* It's fine, we'll just return the empty List */
224 return quarks;
225 }
226 quarks.add(quark);
227 return quarks;
228 }
229
230 try {
231 if (prefix.size() == 0) {
232 /*
233 * If 'prefix' is empty, this means the wildcard was the first
234 * element. Look for the root node's sub-attributes.
235 */
236 startingAttribute = -1;
237 } else {
238 startingAttribute = getQuarkAbsolute(prefixStr);
239 }
240 directChildren = attributeTree.getSubAttributes(startingAttribute,
241 false);
242 } catch (AttributeNotFoundException e) {
243 /* That attribute path did not exist, return the empty array */
244 return quarks;
245 }
246
247 /*
248 * Iterate of all the sub-attributes, and only keep those who match the
249 * 'suffix' part of the initial pattern.
250 */
251 for (int childQuark : directChildren) {
252 int matchingQuark;
253 try {
254 matchingQuark = getQuarkRelative(childQuark, suffixStr);
255 } catch (AttributeNotFoundException e) {
256 continue;
257 }
258 quarks.add(matchingQuark);
259 }
260
261 return quarks;
262 }
263
8d1346f0
AM
264 //--------------------------------------------------------------------------
265 // Methods related to insertions in the history
266 //--------------------------------------------------------------------------
a52fde77 267
8d1346f0 268 @Override
a52fde77 269 public void modifyAttribute(long t, ITmfStateValue value, int attributeQuark)
7e0b2b56
AM
270 throws TimeRangeException, AttributeNotFoundException,
271 StateValueTypeException {
a52fde77
AM
272 transState.processStateChange(t, value, attributeQuark);
273 }
274
8d1346f0 275 @Override
a52fde77
AM
276 public void incrementAttribute(long t, int attributeQuark)
277 throws StateValueTypeException, TimeRangeException,
278 AttributeNotFoundException {
279 int prevValue = queryOngoingState(attributeQuark).unboxInt();
280bbdbb
AM
280 if (prevValue == -1) {
281 /* if the attribute was previously null, start counting at 0 */
282 prevValue = 0;
283 }
a52fde77
AM
284 modifyAttribute(t, TmfStateValue.newValueInt(prevValue + 1),
285 attributeQuark);
286 }
287
8d1346f0 288 @Override
a52fde77
AM
289 public void pushAttribute(long t, ITmfStateValue value, int attributeQuark)
290 throws TimeRangeException, AttributeNotFoundException,
291 StateValueTypeException {
a52fde77
AM
292 Integer stackDepth = 0;
293 int subAttributeQuark;
294 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
295
296 if (previousSV.isNull()) {
297 /*
298 * If the StateValue was null, this means this is the first time we
299 * use this attribute. Leave stackDepth at 0.
300 */
301 } else if (previousSV.getType() == 0) {
302 /* Previous value was an integer, all is good, use it */
303 stackDepth = previousSV.unboxInt();
a52fde77
AM
304 } else {
305 /* Previous state of this attribute was another type? Not good! */
90a25ebe
AM
306 throw new StateValueTypeException();
307 }
308
309 if (stackDepth >= 10) {
310 /*
311 * Limit stackDepth to 10, to avoid having Attribute Trees grow out
312 * of control due to buggy insertions
313 */
314 String message = "Stack limit reached, not pushing"; //$NON-NLS-1$
315 throw new AttributeNotFoundException(message);
a52fde77
AM
316 }
317
318 stackDepth++;
319 subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark,
320 stackDepth.toString());
321
322 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
323 attributeQuark);
90a25ebe 324 modifyAttribute(t, value, subAttributeQuark);
a52fde77
AM
325 }
326
8d1346f0 327 @Override
a52fde77
AM
328 public void popAttribute(long t, int attributeQuark)
329 throws AttributeNotFoundException, TimeRangeException,
330 StateValueTypeException {
a52fde77
AM
331 Integer stackDepth;
332 int subAttributeQuark;
333 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
334
335 if (previousSV.isNull()) {
90a25ebe
AM
336 /* Same as if stackDepth == 0, see below */
337 return;
338 }
339 if (previousSV.getType() != 0) {
a52fde77 340 /*
90a25ebe
AM
341 * The existing value was a string, this doesn't look like a valid
342 * stack attribute.
a52fde77 343 */
90a25ebe 344 throw new StateValueTypeException();
a52fde77
AM
345 }
346
90a25ebe
AM
347 stackDepth = previousSV.unboxInt();
348
a52fde77
AM
349 if (stackDepth == 0) {
350 /*
351 * Trying to pop an empty stack. This often happens at the start of
352 * traces, for example when we see a syscall_exit, without having
353 * the corresponding syscall_entry in the trace. Just ignore
354 * silently.
355 */
356 return;
90a25ebe
AM
357 }
358
359 if (stackDepth < 0) {
a52fde77 360 /* This on the other hand should not happen... */
90a25ebe
AM
361 String message = "A top-level stack attribute " + //$NON-NLS-1$
362 "cannot have a negative integer value."; //$NON-NLS-1$
363 throw new StateValueTypeException(message);
a52fde77
AM
364 }
365
366 /* The attribute should already exist... */
367 subAttributeQuark = getQuarkRelative(attributeQuark,
368 stackDepth.toString());
369
370 stackDepth--;
371 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
372 attributeQuark);
373 removeAttribute(t, subAttributeQuark);
374 }
375
8d1346f0 376 @Override
a52fde77
AM
377 public void removeAttribute(long t, int attributeQuark)
378 throws TimeRangeException, AttributeNotFoundException {
379 assert (attributeQuark >= 0);
c66426fd
AM
380 List<Integer> childAttributes;
381
382 /*
383 * "Nullify our children first, recursively. We pass 'false' because we
384 * handle the recursion ourselves.
385 */
386 childAttributes = attributeTree.getSubAttributes(attributeQuark, false);
a52fde77
AM
387 for (Integer childNodeQuark : childAttributes) {
388 assert (attributeQuark != childNodeQuark);
389 removeAttribute(t, childNodeQuark);
390 }
391 /* Nullify ourselves */
7e0b2b56
AM
392 try {
393 transState.processStateChange(t, TmfStateValue.nullValue(),
394 attributeQuark);
395 } catch (StateValueTypeException e) {
50678114
AM
396 /*
397 * Will not happen since we're inserting null values only, but poor
398 * compiler has no way of knowing this...
7e0b2b56
AM
399 */
400 e.printStackTrace();
401 }
a52fde77
AM
402 }
403
8d1346f0
AM
404 //--------------------------------------------------------------------------
405 // "Current" query/update methods
406 //--------------------------------------------------------------------------
a52fde77 407
8d1346f0 408 @Override
a52fde77
AM
409 public ITmfStateValue queryOngoingState(int attributeQuark)
410 throws AttributeNotFoundException {
411 return transState.getOngoingStateValue(attributeQuark);
412 }
413
8d1346f0 414 @Override
a52fde77
AM
415 public void updateOngoingState(ITmfStateValue newValue, int attributeQuark)
416 throws AttributeNotFoundException {
417 transState.changeOngoingStateValue(attributeQuark, newValue);
418 }
419
8d1346f0
AM
420
421
422 //--------------------------------------------------------------------------
423 // Regular query methods (sent to the back-end)
424 //--------------------------------------------------------------------------
425
426 @Override
427 public synchronized List<ITmfStateInterval> queryFullState(long t)
428 throws TimeRangeException {
429 List<ITmfStateInterval> stateInfo = new ArrayList<ITmfStateInterval>(
430 attributeTree.getNbAttributes());
431
432 /* Bring the size of the array to the current number of attributes */
433 for (int i = 0; i < attributeTree.getNbAttributes(); i++) {
434 stateInfo.add(null);
435 }
436
437 /* Query the storage backend */
438 backend.doQuery(stateInfo, t);
439
440 /*
441 * If we are currently building the history, also query the "ongoing"
442 * states for stuff that might not yet be written to the history.
443 */
444 if (transState.isActive()) {
445 transState.doQuery(stateInfo, t);
446 }
447
448 /*
449 * We should have previously inserted an interval for every attribute.
450 * If we do happen do see a 'null' object here, just replace it with a a
451 * dummy internal with a null value, to avoid NPE's further up.
452 */
453 for (int i = 0; i < stateInfo.size(); i++) {
454 if (stateInfo.get(i) == null) {
455 //logMissingInterval(i, t);
456 stateInfo.set(i, new TmfStateInterval(t, t, i, TmfStateValue.nullValue()));
457 }
458 }
459 return stateInfo;
50678114
AM
460 }
461
8d1346f0
AM
462 @Override
463 public ITmfStateInterval querySingleState(long t, int attributeQuark)
464 throws AttributeNotFoundException, TimeRangeException {
465 ITmfStateInterval ret;
466
467 if (transState.hasInfoAboutStateOf(t, attributeQuark)) {
468 ret = transState.getOngoingInterval(attributeQuark);
469 } else {
470 ret = backend.doSingularQuery(t, attributeQuark);
471 }
472
473 /*
474 * Return a fake interval if we could not find anything in the history.
475 * We do NOT want to return 'null' here.
476 */
477 if (ret == null) {
478 //logMissingInterval(attributeQuark, t);
479 return new TmfStateInterval(t, this.getCurrentEndTime(),
480 attributeQuark, TmfStateValue.nullValue());
481 }
482 return ret;
483 }
484
485 @Override
486 public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
487 long t1, long t2) throws TimeRangeException,
488 AttributeNotFoundException {
489 List<ITmfStateInterval> intervals;
490 ITmfStateInterval currentInterval;
491 long ts, tEnd;
492
493 /* Make sure the time range makes sense */
494 if (t2 <= t1) {
495 throw new TimeRangeException();
496 }
497
498 /* Set the actual, valid end time of the range query */
499 if (t2 > this.getCurrentEndTime()) {
500 tEnd = this.getCurrentEndTime();
501 } else {
502 tEnd = t2;
503 }
504
505 /* Get the initial state at time T1 */
506 intervals = new ArrayList<ITmfStateInterval>();
507 currentInterval = querySingleState(t1, attributeQuark);
508 intervals.add(currentInterval);
509
510 /* Get the following state changes */
511 ts = currentInterval.getEndTime();
512 while (ts != -1 && ts < tEnd) {
513 ts++; /* To "jump over" to the next state in the history */
514 currentInterval = querySingleState(ts, attributeQuark);
515 intervals.add(currentInterval);
516 ts = currentInterval.getEndTime();
517 }
518 return intervals;
519 }
520
521 @Override
522 public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
b5a8d0cc
AM
523 long t1, long t2, long resolution, IProgressMonitor monitor)
524 throws TimeRangeException, AttributeNotFoundException {
8d1346f0
AM
525 List<ITmfStateInterval> intervals;
526 ITmfStateInterval currentInterval;
527 long ts, tEnd;
528
b5a8d0cc
AM
529 if (monitor == null) {
530 monitor = new NullProgressMonitor();
531 }
532
8d1346f0
AM
533 /* Make sure the time range makes sense */
534 if (t2 < t1 || resolution <= 0) {
535 throw new TimeRangeException();
536 }
537
538 /* Set the actual, valid end time of the range query */
539 if (t2 > this.getCurrentEndTime()) {
540 tEnd = this.getCurrentEndTime();
541 } else {
542 tEnd = t2;
543 }
544
545 /* Get the initial state at time T1 */
546 intervals = new ArrayList<ITmfStateInterval>();
547 currentInterval = querySingleState(t1, attributeQuark);
548 intervals.add(currentInterval);
549
550 /*
551 * Iterate over the "resolution points". We skip unneeded queries in the
552 * case the current interval is longer than the resolution.
553 */
554 for (ts = t1; (currentInterval.getEndTime() != -1) && (ts < tEnd);
555 ts += resolution) {
556 if (monitor.isCanceled()) {
557 return intervals;
558 }
559 if (ts <= currentInterval.getEndTime()) {
560 continue;
561 }
562 currentInterval = querySingleState(ts, attributeQuark);
563 intervals.add(currentInterval);
564 }
565
566 /* Add the interval at t2, if it wasn't included already. */
567 if (currentInterval.getEndTime() < tEnd) {
568 currentInterval = querySingleState(tEnd, attributeQuark);
569 intervals.add(currentInterval);
570 }
571 return intervals;
572 }
573
574 //--------------------------------------------------------------------------
575 // Debug methods
576 //--------------------------------------------------------------------------
577
578 static void logMissingInterval(int attribute, long timestamp) {
579 Tracer.traceInfo("No data found in history for attribute " + //$NON-NLS-1$
580 attribute + " at time " + timestamp + //$NON-NLS-1$
581 ", returning dummy interval"); //$NON-NLS-1$
a52fde77
AM
582 }
583
584 /**
585 * Print out the contents of the inner structures.
5df842b3 586 *
a52fde77
AM
587 * @param writer
588 * The PrintWriter in which to print the output
589 */
590 public void debugPrint(PrintWriter writer) {
591 attributeTree.debugPrint(writer);
592 transState.debugPrint(writer);
8d1346f0 593 backend.debugPrint(writer);
a52fde77
AM
594 }
595
8d1346f0 596}
This page took 0.055718 seconds and 5 git commands to generate.