lttng: Fix the last StateSystem unit test
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / 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>
5 *
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
10 *
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.tmf.core.statesystem;
14
15import java.io.PrintWriter;
f94a0bac 16import java.util.LinkedList;
a52fde77
AM
17import java.util.List;
18
19import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
20import org.eclipse.linuxtools.tmf.core.statevalue.StateValueTypeException;
21import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
22
23/**
24 * This is the base class for the StateHistorySystem. It contains all the
25 * current-state-updating methods.
26 *
27 * It's not abstract, as it can be used by itself: in this case, no History tree
28 * will be built underneath (no information will be saved to disk) and it will
29 * only be able to respond to queries to the current, latest time.
30 *
31 * @author alexmont
32 *
33 */
34public class StateSystem {
35
36 /* References to the inner structures */
37 protected AttributeTree attributeTree;
38 protected TransientState transState;
39
40 /**
41 * Constructor. No configuration needed!
42 */
43 public StateSystem() {
44 attributeTree = new AttributeTree(this);
45
46 /* This will tell the builder to discard the intervals */
47 transState = new TransientState(null);
48 }
49
50 /**
51 * @name Quark-retrieving methods
52 */
53
54 /**
55 * Basic quark-retrieving method. Pass an attribute in parameter as an array
56 * of strings, the matching quark will be returned.
57 *
58 * This version will NOT create any new attributes. If an invalid attribute
59 * is requested, an exception will be thrown. This should ideally be used
60 * for doing read-only operations on the system, like queries for example.
61 *
62 * @param attribute
63 * Attribute given as its full path in the Attribute Tree
64 * @return The quark of the requested attribute, if it existed.
65 * @throws AttributeNotFoundException
66 * This exception is thrown if the requested attribute simply
67 * did not exist in the system.
68 */
69 public int getQuarkAbsolute(String... attribute)
70 throws AttributeNotFoundException {
71 return attributeTree.getQuarkDontAdd(-1, attribute);
72 }
73
74 /**
75 * Basic quark-retrieving method. Pass an attribute in parameter as an array
76 * of strings, the matching quark will be returned.
77 *
78 * This version WILL create new attributes: if the attribute passed in
79 * parameter is new in the system, it will be added and its new quark will
80 * be returned.
81 *
82 * @param attribute
83 * Attribute given as its full path in the Attribute Tree
84 * @return The quark of the attribute (which either existed or just got
85 * created)
86 */
87 public int getQuarkAbsoluteAndAdd(String... attribute) {
88 return attributeTree.getQuarkAndAdd(-1, attribute);
89 }
90
91 /**
92 * "Relative path" quark-getting method. Instead of specifying a full path,
93 * if you know the path is relative to another attribute for which you
94 * already have the quark, use this for better performance.
95 *
96 * This is useful for cases where a lot of modifications or queries will
97 * originate from the same branch of the attribute tree : the common part of
98 * the path won't have to be re-hashed for every access.
99 *
100 * This version will NOT create any new attributes. If an invalid attribute
101 * is requested, an exception will be thrown. This should ideally be used
102 * for doing read-only operations on the system, like queries for example.
103 *
104 * @param startingNodeQuark
105 * The quark of the attribute from which 'subPath' originates.
106 * @param subPath
107 * "Rest" of the path to get to the final attribute
108 * @return The matching quark, if it existed
109 * @throws AttributeNotFoundException
110 */
111 public int getQuarkRelative(int startingNodeQuark, String... subPath)
112 throws AttributeNotFoundException {
113 return attributeTree.getQuarkDontAdd(startingNodeQuark, subPath);
114 }
115
116 /**
117 * "Relative path" quark-getting method. Instead of specifying a full path,
118 * if you know the path is relative to another attribute for which you
119 * already have the quark, use this for better performance.
120 *
121 * This is useful for cases where a lot of modifications or queries will
122 * originate from the same branch of the attribute tree : the common part of
123 * the path won't have to be re-hashed for every access.
124 *
125 * This version WILL create new attributes: if the attribute passed in
126 * parameter is new in the system, it will be added and its new quark will
127 * be returned.
128 *
129 * @param startingNodeQuark
130 * The quark of the attribute from which 'subPath' originates.
131 * @param subPath
132 * "Rest" of the path to get to the final attribute
133 * @return The matching quark, either if it's new of just got created.
134 */
135 public int getQuarkRelativeAndAdd(int startingNodeQuark, String... subPath) {
136 return attributeTree.getQuarkAndAdd(startingNodeQuark, subPath);
137 }
138
0a9de3d2
AM
139 /**
140 * Return the sub-attributes of the target attribute, as a List of quarks.
141 *
142 * @param quark
143 * The attribute of which you want to sub-attributes. You can use
144 * "-1" here to specify the root node.
c66426fd
AM
145 * @param recursive
146 * True if you want all recursive sub-attributes, false if you
147 * only want the first level.
0a9de3d2
AM
148 * @return A List of integers, matching the quarks of the sub-attributes.
149 * @throws AttributeNotFoundException
150 * If the quark was not existing or invalid.
151 */
c66426fd 152 public List<Integer> getSubAttributes(int quark, boolean recursive)
0a9de3d2 153 throws AttributeNotFoundException {
c66426fd 154 return attributeTree.getSubAttributes(quark, recursive);
0a9de3d2
AM
155 }
156
f94a0bac
AM
157 /**
158 * Batch quark-retrieving method. This method allows you to specify a path
159 * pattern which includes a wildcard "*" somewhere. It will check all the
160 * existing attributes in the attribute tree and return those who match the
161 * pattern.
162 *
163 * For example, passing ("Threads", "*", "Exec_mode") will return the list
164 * of quarks for attributes "Threads/1000/Exec_mode",
165 * "Threads/1500/Exec_mode", and so on, depending on what exists at this
166 * time in the attribute tree.
167 *
168 * If no wildcard is specified, the behavior is the same as
169 * getQuarkAbsolute() (except it will return a List with one entry). This
170 * method will never create new attributes.
171 *
172 * Only one wildcard "*" is supported at this time.
173 *
174 * @param pattern
175 * The array of strings representing the pattern to look for. It
176 * should ideally contain one entry that is only a "*".
177 * @return A List of attribute quarks, representing attributes that matched
178 * the pattern. If no attribute matched, the list will be empty (but
179 * not null).
180 */
181 public List<Integer> getQuarks(String... pattern) {
182 List<Integer> quarks = new LinkedList<Integer>();
183 List<String> prefix = new LinkedList<String>();
184 List<String> suffix = new LinkedList<String>();
185 boolean split = false;
186 String[] prefixStr;
187 String[] suffixStr;
188 List<Integer> directChildren;
189 int startingAttribute;
190
191 /* Fill the "prefix" and "suffix" parts of the pattern around the '*' */
192 for (String entry : pattern) {
193 if (entry.equals("*")) { //$NON-NLS-1$
194 if (split) {
195 /*
196 * Split was already true? This means there was more than
197 * one wildcard. This is not supported, return an empty
198 * list.
199 */
200 return quarks;
201 }
202 split = true;
203 continue;
204 }
205
206 if (split) {
207 suffix.add(entry);
208 } else {
209 prefix.add(entry);
210 }
211 }
212 prefixStr = prefix.toArray(new String[prefix.size()]);
213 suffixStr = suffix.toArray(new String[suffix.size()]);
214
215 /*
216 * If there was no wildcard, we'll only return the one matching
217 * attribute, if there is one.
218 */
219 if (split == false) {
220 int quark;
221 try {
222 quark = getQuarkAbsolute(prefixStr);
223 } catch (AttributeNotFoundException e) {
224 /* It's fine, we'll just return the empty List */
225 return quarks;
226 }
227 quarks.add(quark);
228 return quarks;
229 }
230
231 try {
232 if (prefix.size() == 0) {
233 /*
234 * If 'prefix' is empty, this means the wildcard was the first
235 * element. Look for the root node's sub-attributes.
236 */
237 startingAttribute = -1;
238 } else {
239 startingAttribute = getQuarkAbsolute(prefixStr);
240 }
241 directChildren = attributeTree.getSubAttributes(startingAttribute,
242 false);
243 } catch (AttributeNotFoundException e) {
244 /* That attribute path did not exist, return the empty array */
245 return quarks;
246 }
247
248 /*
249 * Iterate of all the sub-attributes, and only keep those who match the
250 * 'suffix' part of the initial pattern.
251 */
252 for (int childQuark : directChildren) {
253 int matchingQuark;
254 try {
255 matchingQuark = getQuarkRelative(childQuark, suffixStr);
256 } catch (AttributeNotFoundException e) {
257 continue;
258 }
259 quarks.add(matchingQuark);
260 }
261
262 return quarks;
263 }
264
a52fde77
AM
265 /**
266 * @name External methods related to insertions in the history -
267 */
268
269 /**
270 * Basic attribute modification method, we simply specify a new value, for a
271 * given attribute, effective at the given timestamp.
272 *
273 * @param t
274 * Timestamp of the state change
275 * @param value
276 * The State Value we want to assign to the attribute
277 * @param attributeQuark
278 * Integer value of the quark corresponding to the attribute we
279 * want to modify
280 * @throws TimeRangeException
281 * If the requested time is outside of the trace's range
282 * @throws AttributeNotFoundException
283 * If the requested attribute quark is invalid
284 */
285 public void modifyAttribute(long t, ITmfStateValue value, int attributeQuark)
286 throws TimeRangeException, AttributeNotFoundException {
287 transState.processStateChange(t, value, attributeQuark);
288 }
289
290 /**
291 * Increment attribute method. Reads the current value of a given integer
292 * attribute (this value is right now in the Transient State), and increment
293 * it by 1. Useful for statistics.
294 *
295 * @param t
296 * Timestamp of the state change
297 * @param attributeQuark
298 * Attribute to increment. If it doesn't exist it will be added,
299 * with a new value of 1.
300 * @throws StateValueTypeException
301 * If the attribute already exists but is not of type Integer
302 * @throws TimeRangeException
303 * If the given timestamp is invalid
304 * @throws AttributeNotFoundException
305 * If the quark is invalid
306 */
307 public void incrementAttribute(long t, int attributeQuark)
308 throws StateValueTypeException, TimeRangeException,
309 AttributeNotFoundException {
310 int prevValue = queryOngoingState(attributeQuark).unboxInt();
311 /* prevValue should be == 0 if the attribute wasn't existing before */
312 modifyAttribute(t, TmfStateValue.newValueInt(prevValue + 1),
313 attributeQuark);
314 }
315
316 /**
317 * "Push" helper method. This uses the given integer attribute as a stack:
318 * The value of that attribute will represent the stack depth (always >= 1).
319 * Sub-attributes will be created, their base-name will be the position in
320 * the stack (1, 2, etc.) and their value will be the state value 'value'
321 * that was pushed to this position.
322 *
323 * @param t
324 * Timestamp of the state change
325 * @param value
326 * State value to assign to this stack position.
327 * @param attributeQuark
328 * The base attribute to use as a stack. If it does not exist if
329 * will be created (with depth = 1)
330 * @throws TimeRangeException
331 * If the requested timestamp is invalid
332 * @throws AttributeNotFoundException
333 * If the attribute is invalid
334 * @throws StateValueTypeException
335 * If the attribute 'attributeQuark' already exists, but is not
336 * of integer type.
337 */
338 public void pushAttribute(long t, ITmfStateValue value, int attributeQuark)
339 throws TimeRangeException, AttributeNotFoundException,
340 StateValueTypeException {
a52fde77
AM
341 Integer stackDepth = 0;
342 int subAttributeQuark;
343 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
344
345 if (previousSV.isNull()) {
346 /*
347 * If the StateValue was null, this means this is the first time we
348 * use this attribute. Leave stackDepth at 0.
349 */
350 } else if (previousSV.getType() == 0) {
351 /* Previous value was an integer, all is good, use it */
352 stackDepth = previousSV.unboxInt();
a52fde77
AM
353 } else {
354 /* Previous state of this attribute was another type? Not good! */
90a25ebe
AM
355 throw new StateValueTypeException();
356 }
357
358 if (stackDepth >= 10) {
359 /*
360 * Limit stackDepth to 10, to avoid having Attribute Trees grow out
361 * of control due to buggy insertions
362 */
363 String message = "Stack limit reached, not pushing"; //$NON-NLS-1$
364 throw new AttributeNotFoundException(message);
a52fde77
AM
365 }
366
367 stackDepth++;
368 subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark,
369 stackDepth.toString());
370
371 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
372 attributeQuark);
90a25ebe 373 modifyAttribute(t, value, subAttributeQuark);
a52fde77
AM
374 }
375
376 /**
377 * Antagonist of the pushAttribute(), pops the top-most attribute on the
378 * stack-attribute. If this brings it back to depth = 0, the attribute is
379 * kept with depth = 0. If the value is already 0, or if the attribute
380 * doesn't exist, nothing is done.
381 *
382 * @param t
383 * Timestamp of the state change
384 * @param attributeQuark
385 * Quark of the stack-attribute to pop
386 * @throws AttributeNotFoundException
387 * If the attribute is invalid
388 * @throws TimeRangeException
389 * If the timestamp is invalid
390 * @throws StateValueTypeException
391 * If the target attribute already exists, but its state value
392 * type is invalid (not an integer)
393 */
394 public void popAttribute(long t, int attributeQuark)
395 throws AttributeNotFoundException, TimeRangeException,
396 StateValueTypeException {
a52fde77
AM
397 Integer stackDepth;
398 int subAttributeQuark;
399 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
400
401 if (previousSV.isNull()) {
90a25ebe
AM
402 /* Same as if stackDepth == 0, see below */
403 return;
404 }
405 if (previousSV.getType() != 0) {
a52fde77 406 /*
90a25ebe
AM
407 * The existing value was a string, this doesn't look like a valid
408 * stack attribute.
a52fde77 409 */
90a25ebe 410 throw new StateValueTypeException();
a52fde77
AM
411 }
412
90a25ebe
AM
413 stackDepth = previousSV.unboxInt();
414
a52fde77
AM
415 if (stackDepth == 0) {
416 /*
417 * Trying to pop an empty stack. This often happens at the start of
418 * traces, for example when we see a syscall_exit, without having
419 * the corresponding syscall_entry in the trace. Just ignore
420 * silently.
421 */
422 return;
90a25ebe
AM
423 }
424
425 if (stackDepth < 0) {
a52fde77 426 /* This on the other hand should not happen... */
90a25ebe
AM
427 String message = "A top-level stack attribute " + //$NON-NLS-1$
428 "cannot have a negative integer value."; //$NON-NLS-1$
429 throw new StateValueTypeException(message);
a52fde77
AM
430 }
431
432 /* The attribute should already exist... */
433 subAttributeQuark = getQuarkRelative(attributeQuark,
434 stackDepth.toString());
435
436 stackDepth--;
437 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
438 attributeQuark);
439 removeAttribute(t, subAttributeQuark);
440 }
441
442 /**
443 * Remove attribute method. Similar to the above modify- methods, with value
444 * = 0 / null, except we will also "nullify" all the sub-contents of the
445 * requested path (a bit like "rm -rf")
446 *
447 * @param t
448 * Timestamp of the state change
449 * @param attributeQuark
450 * Attribute to remove
451 * @throws TimeRangeException
452 * If the timestamp is invalid
453 * @throws AttributeNotFoundException
454 * If the quark is invalid
455 */
456 public void removeAttribute(long t, int attributeQuark)
457 throws TimeRangeException, AttributeNotFoundException {
458 assert (attributeQuark >= 0);
c66426fd
AM
459 List<Integer> childAttributes;
460
461 /*
462 * "Nullify our children first, recursively. We pass 'false' because we
463 * handle the recursion ourselves.
464 */
465 childAttributes = attributeTree.getSubAttributes(attributeQuark, false);
a52fde77
AM
466 for (Integer childNodeQuark : childAttributes) {
467 assert (attributeQuark != childNodeQuark);
468 removeAttribute(t, childNodeQuark);
469 }
470 /* Nullify ourselves */
471 transState.processStateChange(t, TmfStateValue.nullValue(),
472 attributeQuark);
473 }
474
475 /**
476 * @name "Current" query/update methods -
477 */
478
479 /**
480 * Returns the current state value we have (in the Transient State) for the
481 * given attribute.
482 *
483 * This is useful even for a StateHistorySystem, as we are guaranteed it
484 * will only do a memory access and not go look on disk (and we don't even
485 * have to provide a timestamp!)
486 *
487 * @param attributeQuark
488 * For which attribute we want the current state
489 * @return The State value that's "current" for this attribute
490 * @throws AttributeNotFoundException
491 * If the requested attribute is invalid
492 */
493 public ITmfStateValue queryOngoingState(int attributeQuark)
494 throws AttributeNotFoundException {
495 return transState.getOngoingStateValue(attributeQuark);
496 }
497
498 /**
499 * Modify a current "ongoing" state (instead of inserting a state change,
500 * like modifyAttribute() and others).
501 *
502 * This can be used to update the value of a previous state change, for
503 * example when we get information at the end of the state and not at the
504 * beginning. (return values of system calls, etc.)
505 *
506 * Note that past states can only be modified while they are still in
507 * memory, so only the "current state" can be updated. Once they get
508 * committed to disk (by inserting a new state change) it becomes too late.
509 *
510 * @param newValue
511 * The new value that will overwrite the "current" one.
512 * @param attributeQuark
513 * For which attribute in the system
514 * @throws AttributeNotFoundException
515 * If the requested attribute is invalid
516 */
517 public void updateOngoingState(ITmfStateValue newValue, int attributeQuark)
518 throws AttributeNotFoundException {
519 transState.changeOngoingStateValue(attributeQuark, newValue);
520 }
521
522 /**
523 * @name Debugging methods
524 */
525
526 /**
527 * This returns the slash-separated path of an attribute by providing its
528 * quark
529 *
530 * @param attributeQuark
531 * The quark of the attribute we want
532 * @return One single string separated with '/', like a filesystem path
533 */
534 public String getFullAttributePath(int attributeQuark) {
535 return attributeTree.getFullAttributeName(attributeQuark);
536 }
537
538 /**
539 * Print out the contents of the inner structures.
540 *
541 * @param writer
542 * The PrintWriter in which to print the output
543 */
544 public void debugPrint(PrintWriter writer) {
545 attributeTree.debugPrint(writer);
546 transState.debugPrint(writer);
547 }
548
549}
This page took 0.046855 seconds and 5 git commands to generate.