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
284 * @throws StateValueTypeException
285 * If the inserted state value's type does not match what is
286 * already assigned to this attribute.
288 public void modifyAttribute(long t
, ITmfStateValue value
, int attributeQuark
)
289 throws TimeRangeException
, AttributeNotFoundException
,
290 StateValueTypeException
{
291 transState
.processStateChange(t
, value
, attributeQuark
);
295 * Increment attribute method. Reads the current value of a given integer
296 * attribute (this value is right now in the Transient State), and increment
297 * it by 1. Useful for statistics.
300 * Timestamp of the state change
301 * @param attributeQuark
302 * Attribute to increment. If it doesn't exist it will be added,
303 * with a new value of 1.
304 * @throws StateValueTypeException
305 * If the attribute already exists but is not of type Integer
306 * @throws TimeRangeException
307 * If the given timestamp is invalid
308 * @throws AttributeNotFoundException
309 * If the quark is invalid
311 public void incrementAttribute(long t
, int attributeQuark
)
312 throws StateValueTypeException
, TimeRangeException
,
313 AttributeNotFoundException
{
314 int prevValue
= queryOngoingState(attributeQuark
).unboxInt();
315 /* prevValue should be == 0 if the attribute wasn't existing before */
316 modifyAttribute(t
, TmfStateValue
.newValueInt(prevValue
+ 1),
321 * "Push" helper method. This uses the given integer attribute as a stack:
322 * The value of that attribute will represent the stack depth (always >= 1).
323 * Sub-attributes will be created, their base-name will be the position in
324 * the stack (1, 2, etc.) and their value will be the state value 'value'
325 * that was pushed to this position.
328 * Timestamp of the state change
330 * State value to assign to this stack position.
331 * @param attributeQuark
332 * The base attribute to use as a stack. If it does not exist if
333 * will be created (with depth = 1)
334 * @throws TimeRangeException
335 * If the requested timestamp is invalid
336 * @throws AttributeNotFoundException
337 * If the attribute is invalid
338 * @throws StateValueTypeException
339 * If the attribute 'attributeQuark' already exists, but is not
342 public void pushAttribute(long t
, ITmfStateValue value
, int attributeQuark
)
343 throws TimeRangeException
, AttributeNotFoundException
,
344 StateValueTypeException
{
345 Integer stackDepth
= 0;
346 int subAttributeQuark
;
347 ITmfStateValue previousSV
= transState
.getOngoingStateValue(attributeQuark
);
349 if (previousSV
.isNull()) {
351 * If the StateValue was null, this means this is the first time we
352 * use this attribute. Leave stackDepth at 0.
354 } else if (previousSV
.getType() == 0) {
355 /* Previous value was an integer, all is good, use it */
356 stackDepth
= previousSV
.unboxInt();
358 /* Previous state of this attribute was another type? Not good! */
359 throw new StateValueTypeException();
362 if (stackDepth
>= 10) {
364 * Limit stackDepth to 10, to avoid having Attribute Trees grow out
365 * of control due to buggy insertions
367 String message
= "Stack limit reached, not pushing"; //$NON-NLS-1$
368 throw new AttributeNotFoundException(message
);
372 subAttributeQuark
= getQuarkRelativeAndAdd(attributeQuark
,
373 stackDepth
.toString());
375 modifyAttribute(t
, TmfStateValue
.newValueInt(stackDepth
),
377 modifyAttribute(t
, value
, subAttributeQuark
);
381 * Antagonist of the pushAttribute(), pops the top-most attribute on the
382 * stack-attribute. If this brings it back to depth = 0, the attribute is
383 * kept with depth = 0. If the value is already 0, or if the attribute
384 * doesn't exist, nothing is done.
387 * Timestamp of the state change
388 * @param attributeQuark
389 * Quark of the stack-attribute to pop
390 * @throws AttributeNotFoundException
391 * If the attribute is invalid
392 * @throws TimeRangeException
393 * If the timestamp is invalid
394 * @throws StateValueTypeException
395 * If the target attribute already exists, but its state value
396 * type is invalid (not an integer)
398 public void popAttribute(long t
, int attributeQuark
)
399 throws AttributeNotFoundException
, TimeRangeException
,
400 StateValueTypeException
{
402 int subAttributeQuark
;
403 ITmfStateValue previousSV
= transState
.getOngoingStateValue(attributeQuark
);
405 if (previousSV
.isNull()) {
406 /* Same as if stackDepth == 0, see below */
409 if (previousSV
.getType() != 0) {
411 * The existing value was a string, this doesn't look like a valid
414 throw new StateValueTypeException();
417 stackDepth
= previousSV
.unboxInt();
419 if (stackDepth
== 0) {
421 * Trying to pop an empty stack. This often happens at the start of
422 * traces, for example when we see a syscall_exit, without having
423 * the corresponding syscall_entry in the trace. Just ignore
429 if (stackDepth
< 0) {
430 /* This on the other hand should not happen... */
431 String message
= "A top-level stack attribute " + //$NON-NLS-1$
432 "cannot have a negative integer value."; //$NON-NLS-1$
433 throw new StateValueTypeException(message
);
436 /* The attribute should already exist... */
437 subAttributeQuark
= getQuarkRelative(attributeQuark
,
438 stackDepth
.toString());
441 modifyAttribute(t
, TmfStateValue
.newValueInt(stackDepth
),
443 removeAttribute(t
, subAttributeQuark
);
447 * Remove attribute method. Similar to the above modify- methods, with value
448 * = 0 / null, except we will also "nullify" all the sub-contents of the
449 * requested path (a bit like "rm -rf")
452 * Timestamp of the state change
453 * @param attributeQuark
454 * Attribute to remove
455 * @throws TimeRangeException
456 * If the timestamp is invalid
457 * @throws AttributeNotFoundException
458 * If the quark is invalid
460 public void removeAttribute(long t
, int attributeQuark
)
461 throws TimeRangeException
, AttributeNotFoundException
{
462 assert (attributeQuark
>= 0);
463 List
<Integer
> childAttributes
;
466 * "Nullify our children first, recursively. We pass 'false' because we
467 * handle the recursion ourselves.
469 childAttributes
= attributeTree
.getSubAttributes(attributeQuark
, false);
470 for (Integer childNodeQuark
: childAttributes
) {
471 assert (attributeQuark
!= childNodeQuark
);
472 removeAttribute(t
, childNodeQuark
);
474 /* Nullify ourselves */
476 transState
.processStateChange(t
, TmfStateValue
.nullValue(),
478 } catch (StateValueTypeException e
) {
480 * Will not happen since we're inserting null values only, but
481 * poor compiler has no way of knowing this...
488 * @name "Current" query/update methods -
492 * Returns the current state value we have (in the Transient State) for the
495 * This is useful even for a StateHistorySystem, as we are guaranteed it
496 * will only do a memory access and not go look on disk (and we don't even
497 * have to provide a timestamp!)
499 * @param attributeQuark
500 * For which attribute we want the current state
501 * @return The State value that's "current" for this attribute
502 * @throws AttributeNotFoundException
503 * If the requested attribute is invalid
505 public ITmfStateValue
queryOngoingState(int attributeQuark
)
506 throws AttributeNotFoundException
{
507 return transState
.getOngoingStateValue(attributeQuark
);
511 * Modify a current "ongoing" state (instead of inserting a state change,
512 * like modifyAttribute() and others).
514 * This can be used to update the value of a previous state change, for
515 * example when we get information at the end of the state and not at the
516 * beginning. (return values of system calls, etc.)
518 * Note that past states can only be modified while they are still in
519 * memory, so only the "current state" can be updated. Once they get
520 * committed to disk (by inserting a new state change) it becomes too late.
523 * The new value that will overwrite the "current" one.
524 * @param attributeQuark
525 * For which attribute in the system
526 * @throws AttributeNotFoundException
527 * If the requested attribute is invalid
529 public void updateOngoingState(ITmfStateValue newValue
, int attributeQuark
)
530 throws AttributeNotFoundException
{
531 transState
.changeOngoingStateValue(attributeQuark
, newValue
);
535 * @name Debugging methods
539 * This returns the slash-separated path of an attribute by providing its
542 * @param attributeQuark
543 * The quark of the attribute we want
544 * @return One single string separated with '/', like a filesystem path
546 public String
getFullAttributePath(int attributeQuark
) {
547 return attributeTree
.getFullAttributeName(attributeQuark
);
551 * Print out the contents of the inner structures.
554 * The PrintWriter in which to print the output
556 public void debugPrint(PrintWriter writer
) {
557 attributeTree
.debugPrint(writer
);
558 transState
.debugPrint(writer
);