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>
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
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.statesystem
;
15 import java
.io
.PrintWriter
;
16 import java
.util
.LinkedList
;
17 import java
.util
.List
;
19 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
20 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.StateValueTypeException
;
21 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.TmfStateValue
;
24 * This is the base class for the StateHistorySystem. It contains all the
25 * current-state-updating methods.
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.
34 public class StateSystem
{
36 /* References to the inner structures */
37 protected AttributeTree attributeTree
;
38 protected TransientState transState
;
41 * Constructor. No configuration needed!
43 public StateSystem() {
44 attributeTree
= new AttributeTree(this);
46 /* This will tell the builder to discard the intervals */
47 transState
= new TransientState(null);
51 * @name Quark-retrieving methods
55 * Basic quark-retrieving method. Pass an attribute in parameter as an array
56 * of strings, the matching quark will be returned.
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.
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.
69 public int getQuarkAbsolute(String
... attribute
)
70 throws AttributeNotFoundException
{
71 return attributeTree
.getQuarkDontAdd(-1, attribute
);
75 * Basic quark-retrieving method. Pass an attribute in parameter as an array
76 * of strings, the matching quark will be returned.
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
83 * Attribute given as its full path in the Attribute Tree
84 * @return The quark of the attribute (which either existed or just got
87 public int getQuarkAbsoluteAndAdd(String
... attribute
) {
88 return attributeTree
.getQuarkAndAdd(-1, attribute
);
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.
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.
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.
104 * @param startingNodeQuark
105 * The quark of the attribute from which 'subPath' originates.
107 * "Rest" of the path to get to the final attribute
108 * @return The matching quark, if it existed
109 * @throws AttributeNotFoundException
111 public int getQuarkRelative(int startingNodeQuark
, String
... subPath
)
112 throws AttributeNotFoundException
{
113 return attributeTree
.getQuarkDontAdd(startingNodeQuark
, subPath
);
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.
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.
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
129 * @param startingNodeQuark
130 * The quark of the attribute from which 'subPath' originates.
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.
135 public int getQuarkRelativeAndAdd(int startingNodeQuark
, String
... subPath
) {
136 return attributeTree
.getQuarkAndAdd(startingNodeQuark
, subPath
);
140 * Return the sub-attributes of the target attribute, as a List of quarks.
143 * The attribute of which you want to sub-attributes. You can use
144 * "-1" here to specify the root node.
146 * True if you want all recursive sub-attributes, false if you
147 * only want the first level.
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.
152 public List
<Integer
> getSubAttributes(int quark
, boolean recursive
)
153 throws AttributeNotFoundException
{
154 return attributeTree
.getSubAttributes(quark
, recursive
);
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
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.
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.
172 * Only one wildcard "*" is supported at this time.
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
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;
188 List
<Integer
> directChildren
;
189 int startingAttribute
;
191 /* Fill the "prefix" and "suffix" parts of the pattern around the '*' */
192 for (String entry
: pattern
) {
193 if (entry
.equals("*")) { //$NON-NLS-1$
196 * Split was already true? This means there was more than
197 * one wildcard. This is not supported, return an empty
212 prefixStr
= prefix
.toArray(new String
[prefix
.size()]);
213 suffixStr
= suffix
.toArray(new String
[suffix
.size()]);
216 * If there was no wildcard, we'll only return the one matching
217 * attribute, if there is one.
219 if (split
== false) {
222 quark
= getQuarkAbsolute(prefixStr
);
223 } catch (AttributeNotFoundException e
) {
224 /* It's fine, we'll just return the empty List */
232 if (prefix
.size() == 0) {
234 * If 'prefix' is empty, this means the wildcard was the first
235 * element. Look for the root node's sub-attributes.
237 startingAttribute
= -1;
239 startingAttribute
= getQuarkAbsolute(prefixStr
);
241 directChildren
= attributeTree
.getSubAttributes(startingAttribute
,
243 } catch (AttributeNotFoundException e
) {
244 /* That attribute path did not exist, return the empty array */
249 * Iterate of all the sub-attributes, and only keep those who match the
250 * 'suffix' part of the initial pattern.
252 for (int childQuark
: directChildren
) {
255 matchingQuark
= getQuarkRelative(childQuark
, suffixStr
);
256 } catch (AttributeNotFoundException e
) {
259 quarks
.add(matchingQuark
);
266 * @name External methods related to insertions in the history -
270 * Basic attribute modification method, we simply specify a new value, for a
271 * given attribute, effective at the given timestamp.
274 * Timestamp of the state change
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
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
285 public void modifyAttribute(long t
, ITmfStateValue value
, int attributeQuark
)
286 throws TimeRangeException
, AttributeNotFoundException
{
287 transState
.processStateChange(t
, value
, attributeQuark
);
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.
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
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),
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.
324 * Timestamp of the state change
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
338 public void pushAttribute(long t
, ITmfStateValue value
, int attributeQuark
)
339 throws TimeRangeException
, AttributeNotFoundException
,
340 StateValueTypeException
{
341 assert (attributeQuark
>= 0);
342 Integer stackDepth
= 0;
343 int subAttributeQuark
;
344 ITmfStateValue previousSV
= transState
.getOngoingStateValue(attributeQuark
);
346 if (previousSV
.isNull()) {
348 * If the StateValue was null, this means this is the first time we
349 * use this attribute. Leave stackDepth at 0.
351 } else if (previousSV
.getType() == 0) {
352 /* Previous value was an integer, all is good, use it */
353 stackDepth
= previousSV
.unboxInt();
354 if (stackDepth
>= 10) {
356 * Limit stackDepth to 10, to avoid having Attribute Trees grow
357 * out of control due to buggy insertions
362 /* Previous state of this attribute was another type? Not good! */
367 subAttributeQuark
= getQuarkRelativeAndAdd(attributeQuark
,
368 stackDepth
.toString());
370 modifyAttribute(t
, TmfStateValue
.newValueInt(stackDepth
),
372 transState
.processStateChange(t
, value
, subAttributeQuark
);
376 * Antagonist of the pushAttribute(), pops the top-most attribute on the
377 * stack-attribute. If this brings it back to depth = 0, the attribute is
378 * kept with depth = 0. If the value is already 0, or if the attribute
379 * doesn't exist, nothing is done.
382 * Timestamp of the state change
383 * @param attributeQuark
384 * Quark of the stack-attribute to pop
385 * @throws AttributeNotFoundException
386 * If the attribute is invalid
387 * @throws TimeRangeException
388 * If the timestamp is invalid
389 * @throws StateValueTypeException
390 * If the target attribute already exists, but its state value
391 * type is invalid (not an integer)
393 public void popAttribute(long t
, int attributeQuark
)
394 throws AttributeNotFoundException
, TimeRangeException
,
395 StateValueTypeException
{
396 assert (attributeQuark
>= 0);
398 int subAttributeQuark
;
399 ITmfStateValue previousSV
= transState
.getOngoingStateValue(attributeQuark
);
401 if (previousSV
.isNull()) {
403 * If the StateValue was null, this means this is the first time we
404 * use this attribute.
408 assert (previousSV
.getType() == 0);
409 stackDepth
= previousSV
.unboxInt();
412 if (stackDepth
== 0) {
414 * Trying to pop an empty stack. This often happens at the start of
415 * traces, for example when we see a syscall_exit, without having
416 * the corresponding syscall_entry in the trace. Just ignore
420 } else if (stackDepth
< 0) {
421 /* This on the other hand should not happen... */
425 /* The attribute should already exist... */
426 subAttributeQuark
= getQuarkRelative(attributeQuark
,
427 stackDepth
.toString());
430 modifyAttribute(t
, TmfStateValue
.newValueInt(stackDepth
),
432 removeAttribute(t
, subAttributeQuark
);
436 * Remove attribute method. Similar to the above modify- methods, with value
437 * = 0 / null, except we will also "nullify" all the sub-contents of the
438 * requested path (a bit like "rm -rf")
441 * Timestamp of the state change
442 * @param attributeQuark
443 * Attribute to remove
444 * @throws TimeRangeException
445 * If the timestamp is invalid
446 * @throws AttributeNotFoundException
447 * If the quark is invalid
449 public void removeAttribute(long t
, int attributeQuark
)
450 throws TimeRangeException
, AttributeNotFoundException
{
451 assert (attributeQuark
>= 0);
452 List
<Integer
> childAttributes
;
455 * "Nullify our children first, recursively. We pass 'false' because we
456 * handle the recursion ourselves.
458 childAttributes
= attributeTree
.getSubAttributes(attributeQuark
, false);
459 for (Integer childNodeQuark
: childAttributes
) {
460 assert (attributeQuark
!= childNodeQuark
);
461 removeAttribute(t
, childNodeQuark
);
463 /* Nullify ourselves */
464 transState
.processStateChange(t
, TmfStateValue
.nullValue(),
469 * @name "Current" query/update methods -
473 * Returns the current state value we have (in the Transient State) for the
476 * This is useful even for a StateHistorySystem, as we are guaranteed it
477 * will only do a memory access and not go look on disk (and we don't even
478 * have to provide a timestamp!)
480 * @param attributeQuark
481 * For which attribute we want the current state
482 * @return The State value that's "current" for this attribute
483 * @throws AttributeNotFoundException
484 * If the requested attribute is invalid
486 public ITmfStateValue
queryOngoingState(int attributeQuark
)
487 throws AttributeNotFoundException
{
488 return transState
.getOngoingStateValue(attributeQuark
);
492 * Modify a current "ongoing" state (instead of inserting a state change,
493 * like modifyAttribute() and others).
495 * This can be used to update the value of a previous state change, for
496 * example when we get information at the end of the state and not at the
497 * beginning. (return values of system calls, etc.)
499 * Note that past states can only be modified while they are still in
500 * memory, so only the "current state" can be updated. Once they get
501 * committed to disk (by inserting a new state change) it becomes too late.
504 * The new value that will overwrite the "current" one.
505 * @param attributeQuark
506 * For which attribute in the system
507 * @throws AttributeNotFoundException
508 * If the requested attribute is invalid
510 public void updateOngoingState(ITmfStateValue newValue
, int attributeQuark
)
511 throws AttributeNotFoundException
{
512 transState
.changeOngoingStateValue(attributeQuark
, newValue
);
516 * @name Debugging methods
520 * This returns the slash-separated path of an attribute by providing its
523 * @param attributeQuark
524 * The quark of the attribute we want
525 * @return One single string separated with '/', like a filesystem path
527 public String
getFullAttributePath(int attributeQuark
) {
528 return attributeTree
.getFullAttributeName(attributeQuark
);
532 * Print out the contents of the inner structures.
535 * The PrintWriter in which to print the output
537 public void debugPrint(PrintWriter writer
) {
538 attributeTree
.debugPrint(writer
);
539 transState
.debugPrint(writer
);