Commit | Line | Data |
---|---|---|
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 | ||
13 | package org.eclipse.linuxtools.tmf.core.statesystem; | |
14 | ||
15 | import java.io.PrintWriter; | |
f94a0bac | 16 | import java.util.LinkedList; |
a52fde77 AM |
17 | import java.util.List; |
18 | ||
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; | |
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 | * | |
d26f90fd AM |
31 | * (See IStateSystemQuerier and IStateSystemBuilder for the Javadoc.) |
32 | * | |
a52fde77 AM |
33 | * @author alexmont |
34 | * | |
35 | */ | |
36 | public class StateSystem { | |
37 | ||
38 | /* References to the inner structures */ | |
39 | protected AttributeTree attributeTree; | |
40 | protected TransientState transState; | |
41 | ||
42 | /** | |
43 | * Constructor. No configuration needed! | |
44 | */ | |
45 | public StateSystem() { | |
46 | attributeTree = new AttributeTree(this); | |
47 | ||
48 | /* This will tell the builder to discard the intervals */ | |
49 | transState = new TransientState(null); | |
50 | } | |
51 | ||
52 | /** | |
53 | * @name Quark-retrieving methods | |
54 | */ | |
55 | ||
a52fde77 AM |
56 | public int getQuarkAbsolute(String... attribute) |
57 | throws AttributeNotFoundException { | |
58 | return attributeTree.getQuarkDontAdd(-1, attribute); | |
59 | } | |
60 | ||
a52fde77 AM |
61 | public int getQuarkAbsoluteAndAdd(String... attribute) { |
62 | return attributeTree.getQuarkAndAdd(-1, attribute); | |
63 | } | |
64 | ||
a52fde77 AM |
65 | public int getQuarkRelative(int startingNodeQuark, String... subPath) |
66 | throws AttributeNotFoundException { | |
67 | return attributeTree.getQuarkDontAdd(startingNodeQuark, subPath); | |
68 | } | |
69 | ||
a52fde77 AM |
70 | public int getQuarkRelativeAndAdd(int startingNodeQuark, String... subPath) { |
71 | return attributeTree.getQuarkAndAdd(startingNodeQuark, subPath); | |
72 | } | |
73 | ||
c66426fd | 74 | public List<Integer> getSubAttributes(int quark, boolean recursive) |
0a9de3d2 | 75 | throws AttributeNotFoundException { |
c66426fd | 76 | return attributeTree.getSubAttributes(quark, recursive); |
0a9de3d2 AM |
77 | } |
78 | ||
f94a0bac AM |
79 | public List<Integer> getQuarks(String... pattern) { |
80 | List<Integer> quarks = new LinkedList<Integer>(); | |
81 | List<String> prefix = new LinkedList<String>(); | |
82 | List<String> suffix = new LinkedList<String>(); | |
83 | boolean split = false; | |
84 | String[] prefixStr; | |
85 | String[] suffixStr; | |
86 | List<Integer> directChildren; | |
87 | int startingAttribute; | |
88 | ||
89 | /* Fill the "prefix" and "suffix" parts of the pattern around the '*' */ | |
90 | for (String entry : pattern) { | |
91 | if (entry.equals("*")) { //$NON-NLS-1$ | |
92 | if (split) { | |
93 | /* | |
94 | * Split was already true? This means there was more than | |
95 | * one wildcard. This is not supported, return an empty | |
96 | * list. | |
97 | */ | |
98 | return quarks; | |
99 | } | |
100 | split = true; | |
101 | continue; | |
102 | } | |
103 | ||
104 | if (split) { | |
105 | suffix.add(entry); | |
106 | } else { | |
107 | prefix.add(entry); | |
108 | } | |
109 | } | |
110 | prefixStr = prefix.toArray(new String[prefix.size()]); | |
111 | suffixStr = suffix.toArray(new String[suffix.size()]); | |
112 | ||
113 | /* | |
114 | * If there was no wildcard, we'll only return the one matching | |
115 | * attribute, if there is one. | |
116 | */ | |
117 | if (split == false) { | |
118 | int quark; | |
119 | try { | |
120 | quark = getQuarkAbsolute(prefixStr); | |
121 | } catch (AttributeNotFoundException e) { | |
122 | /* It's fine, we'll just return the empty List */ | |
123 | return quarks; | |
124 | } | |
125 | quarks.add(quark); | |
126 | return quarks; | |
127 | } | |
128 | ||
129 | try { | |
130 | if (prefix.size() == 0) { | |
131 | /* | |
132 | * If 'prefix' is empty, this means the wildcard was the first | |
133 | * element. Look for the root node's sub-attributes. | |
134 | */ | |
135 | startingAttribute = -1; | |
136 | } else { | |
137 | startingAttribute = getQuarkAbsolute(prefixStr); | |
138 | } | |
139 | directChildren = attributeTree.getSubAttributes(startingAttribute, | |
140 | false); | |
141 | } catch (AttributeNotFoundException e) { | |
142 | /* That attribute path did not exist, return the empty array */ | |
143 | return quarks; | |
144 | } | |
145 | ||
146 | /* | |
147 | * Iterate of all the sub-attributes, and only keep those who match the | |
148 | * 'suffix' part of the initial pattern. | |
149 | */ | |
150 | for (int childQuark : directChildren) { | |
151 | int matchingQuark; | |
152 | try { | |
153 | matchingQuark = getQuarkRelative(childQuark, suffixStr); | |
154 | } catch (AttributeNotFoundException e) { | |
155 | continue; | |
156 | } | |
157 | quarks.add(matchingQuark); | |
158 | } | |
159 | ||
160 | return quarks; | |
161 | } | |
162 | ||
a52fde77 AM |
163 | /** |
164 | * @name External methods related to insertions in the history - | |
165 | */ | |
166 | ||
a52fde77 | 167 | public void modifyAttribute(long t, ITmfStateValue value, int attributeQuark) |
7e0b2b56 AM |
168 | throws TimeRangeException, AttributeNotFoundException, |
169 | StateValueTypeException { | |
a52fde77 AM |
170 | transState.processStateChange(t, value, attributeQuark); |
171 | } | |
172 | ||
a52fde77 AM |
173 | public void incrementAttribute(long t, int attributeQuark) |
174 | throws StateValueTypeException, TimeRangeException, | |
175 | AttributeNotFoundException { | |
176 | int prevValue = queryOngoingState(attributeQuark).unboxInt(); | |
177 | /* prevValue should be == 0 if the attribute wasn't existing before */ | |
178 | modifyAttribute(t, TmfStateValue.newValueInt(prevValue + 1), | |
179 | attributeQuark); | |
180 | } | |
181 | ||
a52fde77 AM |
182 | public void pushAttribute(long t, ITmfStateValue value, int attributeQuark) |
183 | throws TimeRangeException, AttributeNotFoundException, | |
184 | StateValueTypeException { | |
a52fde77 AM |
185 | Integer stackDepth = 0; |
186 | int subAttributeQuark; | |
187 | ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark); | |
188 | ||
189 | if (previousSV.isNull()) { | |
190 | /* | |
191 | * If the StateValue was null, this means this is the first time we | |
192 | * use this attribute. Leave stackDepth at 0. | |
193 | */ | |
194 | } else if (previousSV.getType() == 0) { | |
195 | /* Previous value was an integer, all is good, use it */ | |
196 | stackDepth = previousSV.unboxInt(); | |
a52fde77 AM |
197 | } else { |
198 | /* Previous state of this attribute was another type? Not good! */ | |
90a25ebe AM |
199 | throw new StateValueTypeException(); |
200 | } | |
201 | ||
202 | if (stackDepth >= 10) { | |
203 | /* | |
204 | * Limit stackDepth to 10, to avoid having Attribute Trees grow out | |
205 | * of control due to buggy insertions | |
206 | */ | |
207 | String message = "Stack limit reached, not pushing"; //$NON-NLS-1$ | |
208 | throw new AttributeNotFoundException(message); | |
a52fde77 AM |
209 | } |
210 | ||
211 | stackDepth++; | |
212 | subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark, | |
213 | stackDepth.toString()); | |
214 | ||
215 | modifyAttribute(t, TmfStateValue.newValueInt(stackDepth), | |
216 | attributeQuark); | |
90a25ebe | 217 | modifyAttribute(t, value, subAttributeQuark); |
a52fde77 AM |
218 | } |
219 | ||
a52fde77 AM |
220 | public void popAttribute(long t, int attributeQuark) |
221 | throws AttributeNotFoundException, TimeRangeException, | |
222 | StateValueTypeException { | |
a52fde77 AM |
223 | Integer stackDepth; |
224 | int subAttributeQuark; | |
225 | ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark); | |
226 | ||
227 | if (previousSV.isNull()) { | |
90a25ebe AM |
228 | /* Same as if stackDepth == 0, see below */ |
229 | return; | |
230 | } | |
231 | if (previousSV.getType() != 0) { | |
a52fde77 | 232 | /* |
90a25ebe AM |
233 | * The existing value was a string, this doesn't look like a valid |
234 | * stack attribute. | |
a52fde77 | 235 | */ |
90a25ebe | 236 | throw new StateValueTypeException(); |
a52fde77 AM |
237 | } |
238 | ||
90a25ebe AM |
239 | stackDepth = previousSV.unboxInt(); |
240 | ||
a52fde77 AM |
241 | if (stackDepth == 0) { |
242 | /* | |
243 | * Trying to pop an empty stack. This often happens at the start of | |
244 | * traces, for example when we see a syscall_exit, without having | |
245 | * the corresponding syscall_entry in the trace. Just ignore | |
246 | * silently. | |
247 | */ | |
248 | return; | |
90a25ebe AM |
249 | } |
250 | ||
251 | if (stackDepth < 0) { | |
a52fde77 | 252 | /* This on the other hand should not happen... */ |
90a25ebe AM |
253 | String message = "A top-level stack attribute " + //$NON-NLS-1$ |
254 | "cannot have a negative integer value."; //$NON-NLS-1$ | |
255 | throw new StateValueTypeException(message); | |
a52fde77 AM |
256 | } |
257 | ||
258 | /* The attribute should already exist... */ | |
259 | subAttributeQuark = getQuarkRelative(attributeQuark, | |
260 | stackDepth.toString()); | |
261 | ||
262 | stackDepth--; | |
263 | modifyAttribute(t, TmfStateValue.newValueInt(stackDepth), | |
264 | attributeQuark); | |
265 | removeAttribute(t, subAttributeQuark); | |
266 | } | |
267 | ||
a52fde77 AM |
268 | public void removeAttribute(long t, int attributeQuark) |
269 | throws TimeRangeException, AttributeNotFoundException { | |
270 | assert (attributeQuark >= 0); | |
c66426fd AM |
271 | List<Integer> childAttributes; |
272 | ||
273 | /* | |
274 | * "Nullify our children first, recursively. We pass 'false' because we | |
275 | * handle the recursion ourselves. | |
276 | */ | |
277 | childAttributes = attributeTree.getSubAttributes(attributeQuark, false); | |
a52fde77 AM |
278 | for (Integer childNodeQuark : childAttributes) { |
279 | assert (attributeQuark != childNodeQuark); | |
280 | removeAttribute(t, childNodeQuark); | |
281 | } | |
282 | /* Nullify ourselves */ | |
7e0b2b56 AM |
283 | try { |
284 | transState.processStateChange(t, TmfStateValue.nullValue(), | |
285 | attributeQuark); | |
286 | } catch (StateValueTypeException e) { | |
50678114 AM |
287 | /* |
288 | * Will not happen since we're inserting null values only, but poor | |
289 | * compiler has no way of knowing this... | |
7e0b2b56 AM |
290 | */ |
291 | e.printStackTrace(); | |
292 | } | |
a52fde77 AM |
293 | } |
294 | ||
295 | /** | |
296 | * @name "Current" query/update methods - | |
297 | */ | |
298 | ||
a52fde77 AM |
299 | public ITmfStateValue queryOngoingState(int attributeQuark) |
300 | throws AttributeNotFoundException { | |
301 | return transState.getOngoingStateValue(attributeQuark); | |
302 | } | |
303 | ||
a52fde77 AM |
304 | public void updateOngoingState(ITmfStateValue newValue, int attributeQuark) |
305 | throws AttributeNotFoundException { | |
306 | transState.changeOngoingStateValue(attributeQuark, newValue); | |
307 | } | |
308 | ||
50678114 AM |
309 | public String getAttributeName(int attributeQuark) { |
310 | return attributeTree.getAttributeName(attributeQuark); | |
311 | } | |
312 | ||
a52fde77 AM |
313 | public String getFullAttributePath(int attributeQuark) { |
314 | return attributeTree.getFullAttributeName(attributeQuark); | |
315 | } | |
316 | ||
317 | /** | |
318 | * Print out the contents of the inner structures. | |
319 | * | |
320 | * @param writer | |
321 | * The PrintWriter in which to print the output | |
322 | */ | |
323 | public void debugPrint(PrintWriter writer) { | |
324 | attributeTree.debugPrint(writer); | |
325 | transState.debugPrint(writer); | |
326 | } | |
327 | ||
328 | } |