lttng: Explicitely return a StateHistorySystem in kernel traces
[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
7e0b2b56
AM
284 * @throws StateValueTypeException
285 * If the inserted state value's type does not match what is
286 * already assigned to this attribute.
a52fde77
AM
287 */
288 public void modifyAttribute(long t, ITmfStateValue value, int attributeQuark)
7e0b2b56
AM
289 throws TimeRangeException, AttributeNotFoundException,
290 StateValueTypeException {
a52fde77
AM
291 transState.processStateChange(t, value, attributeQuark);
292 }
293
294 /**
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.
298 *
299 * @param t
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
310 */
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),
317 attributeQuark);
318 }
319
320 /**
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.
326 *
327 * @param t
328 * Timestamp of the state change
329 * @param value
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
340 * of integer type.
341 */
342 public void pushAttribute(long t, ITmfStateValue value, int attributeQuark)
343 throws TimeRangeException, AttributeNotFoundException,
344 StateValueTypeException {
a52fde77
AM
345 Integer stackDepth = 0;
346 int subAttributeQuark;
347 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
348
349 if (previousSV.isNull()) {
350 /*
351 * If the StateValue was null, this means this is the first time we
352 * use this attribute. Leave stackDepth at 0.
353 */
354 } else if (previousSV.getType() == 0) {
355 /* Previous value was an integer, all is good, use it */
356 stackDepth = previousSV.unboxInt();
a52fde77
AM
357 } else {
358 /* Previous state of this attribute was another type? Not good! */
90a25ebe
AM
359 throw new StateValueTypeException();
360 }
361
362 if (stackDepth >= 10) {
363 /*
364 * Limit stackDepth to 10, to avoid having Attribute Trees grow out
365 * of control due to buggy insertions
366 */
367 String message = "Stack limit reached, not pushing"; //$NON-NLS-1$
368 throw new AttributeNotFoundException(message);
a52fde77
AM
369 }
370
371 stackDepth++;
372 subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark,
373 stackDepth.toString());
374
375 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
376 attributeQuark);
90a25ebe 377 modifyAttribute(t, value, subAttributeQuark);
a52fde77
AM
378 }
379
380 /**
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.
385 *
386 * @param t
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)
397 */
398 public void popAttribute(long t, int attributeQuark)
399 throws AttributeNotFoundException, TimeRangeException,
400 StateValueTypeException {
a52fde77
AM
401 Integer stackDepth;
402 int subAttributeQuark;
403 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
404
405 if (previousSV.isNull()) {
90a25ebe
AM
406 /* Same as if stackDepth == 0, see below */
407 return;
408 }
409 if (previousSV.getType() != 0) {
a52fde77 410 /*
90a25ebe
AM
411 * The existing value was a string, this doesn't look like a valid
412 * stack attribute.
a52fde77 413 */
90a25ebe 414 throw new StateValueTypeException();
a52fde77
AM
415 }
416
90a25ebe
AM
417 stackDepth = previousSV.unboxInt();
418
a52fde77
AM
419 if (stackDepth == 0) {
420 /*
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
424 * silently.
425 */
426 return;
90a25ebe
AM
427 }
428
429 if (stackDepth < 0) {
a52fde77 430 /* This on the other hand should not happen... */
90a25ebe
AM
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);
a52fde77
AM
434 }
435
436 /* The attribute should already exist... */
437 subAttributeQuark = getQuarkRelative(attributeQuark,
438 stackDepth.toString());
439
440 stackDepth--;
441 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
442 attributeQuark);
443 removeAttribute(t, subAttributeQuark);
444 }
445
446 /**
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")
450 *
451 * @param t
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
459 */
460 public void removeAttribute(long t, int attributeQuark)
461 throws TimeRangeException, AttributeNotFoundException {
462 assert (attributeQuark >= 0);
c66426fd
AM
463 List<Integer> childAttributes;
464
465 /*
466 * "Nullify our children first, recursively. We pass 'false' because we
467 * handle the recursion ourselves.
468 */
469 childAttributes = attributeTree.getSubAttributes(attributeQuark, false);
a52fde77
AM
470 for (Integer childNodeQuark : childAttributes) {
471 assert (attributeQuark != childNodeQuark);
472 removeAttribute(t, childNodeQuark);
473 }
474 /* Nullify ourselves */
7e0b2b56
AM
475 try {
476 transState.processStateChange(t, TmfStateValue.nullValue(),
477 attributeQuark);
478 } catch (StateValueTypeException e) {
479 /*
480 * Will not happen since we're inserting null values only, but
481 * poor compiler has no way of knowing this...
482 */
483 e.printStackTrace();
484 }
a52fde77
AM
485 }
486
487 /**
488 * @name "Current" query/update methods -
489 */
490
491 /**
492 * Returns the current state value we have (in the Transient State) for the
493 * given attribute.
494 *
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!)
498 *
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
504 */
505 public ITmfStateValue queryOngoingState(int attributeQuark)
506 throws AttributeNotFoundException {
507 return transState.getOngoingStateValue(attributeQuark);
508 }
509
510 /**
511 * Modify a current "ongoing" state (instead of inserting a state change,
512 * like modifyAttribute() and others).
513 *
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.)
517 *
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.
521 *
522 * @param newValue
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
528 */
529 public void updateOngoingState(ITmfStateValue newValue, int attributeQuark)
530 throws AttributeNotFoundException {
531 transState.changeOngoingStateValue(attributeQuark, newValue);
532 }
533
534 /**
535 * @name Debugging methods
536 */
537
538 /**
539 * This returns the slash-separated path of an attribute by providing its
540 * quark
541 *
542 * @param attributeQuark
543 * The quark of the attribute we want
544 * @return One single string separated with '/', like a filesystem path
545 */
546 public String getFullAttributePath(int attributeQuark) {
547 return attributeTree.getFullAttributeName(attributeQuark);
548 }
549
550 /**
551 * Print out the contents of the inner structures.
552 *
553 * @param writer
554 * The PrintWriter in which to print the output
555 */
556 public void debugPrint(PrintWriter writer) {
557 attributeTree.debugPrint(writer);
558 transState.debugPrint(writer);
559 }
560
561}
This page took 0.047512 seconds and 5 git commands to generate.