tmf: Add proper public methods to internal.tmf.core.statesystem
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / TransientState.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 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.internal.tmf.core.statesystem;
14
15 import java.io.PrintWriter;
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend;
20 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
21 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
22 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
23 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
24 import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
25 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
26 import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
27 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
28
29 /**
30 * The Transient State is used to build intervals from punctual state changes.
31 * It contains a "state info" vector similar to the "current state", except here
32 * we also record the start time of every state stored in it.
33 *
34 * We can then build {@link ITmfStateInterval}'s, to be inserted in a
35 * {@link IStateHistoryBackend} when we detect state changes : the "start time"
36 * of the interval will be the recorded time we have here, and the "end time"
37 * will be the timestamp of the new state-changing event we just read.
38 *
39 * @author Alexandre Montplaisir
40 */
41 public class TransientState {
42
43 /* Indicates where to insert state changes that we generate */
44 private final IStateHistoryBackend backend;
45
46 private boolean isActive;
47 private long latestTime;
48
49 private List<ITmfStateValue> ongoingStateInfo;
50 private List<Long> ongoingStateStartTimes;
51 private List<Type> stateValueTypes;
52
53 /**
54 * Constructor
55 *
56 * @param backend
57 * The back-end in which to insert the generated state intervals
58 */
59 public TransientState(IStateHistoryBackend backend) {
60 this.backend = backend;
61 isActive = true;
62 ongoingStateInfo = new ArrayList<>();
63 ongoingStateStartTimes = new ArrayList<>();
64 stateValueTypes = new ArrayList<>();
65
66 if (backend != null) {
67 latestTime = backend.getStartTime();
68 } else {
69 latestTime = 0;
70 }
71 }
72
73 /**
74 * Get the latest time we have seen so far.
75 *
76 * @return The latest time seen in the transient state
77 */
78 public long getLatestTime() {
79 return latestTime;
80 }
81
82 /**
83 * Retrieve the ongoing state value for a given index (attribute quark).
84 *
85 * @param quark
86 * The quark of the attribute to look for
87 * @return The corresponding state value
88 * @throws AttributeNotFoundException
89 * If the quark is invalid
90 */
91 public ITmfStateValue getOngoingStateValue(int quark) throws AttributeNotFoundException {
92 checkValidAttribute(quark);
93 return ongoingStateInfo.get(quark);
94 }
95
96 /**
97 * Retrieve the start time of the state in which the given attribute is in.
98 *
99 * @param quark
100 * The quark of the attribute to look for
101 * @return The start time of the current state for this attribute
102 * @throws AttributeNotFoundException
103 * If the quark is invalid
104 */
105 public long getOngoingStartTime(int quark) throws AttributeNotFoundException {
106 checkValidAttribute(quark);
107 return ongoingStateStartTimes.get(quark);
108 }
109
110 /**
111 * Modify the current state for a given attribute. This will not update the
112 * "ongoing state start time" in any way, so be careful when using this.
113 *
114 * @param quark
115 * The quark of the attribute to modify
116 * @param newValue
117 * The state value the attribute should have
118 * @throws AttributeNotFoundException
119 * If the quark is invalid
120 */
121 public void changeOngoingStateValue(int quark, ITmfStateValue newValue)
122 throws AttributeNotFoundException {
123 checkValidAttribute(quark);
124 ongoingStateInfo.set(quark, newValue);
125 }
126
127 /**
128 * Convenience method to return the "ongoing" value for a given attribute as
129 * a dummy interval whose end time = -1 (since we don't know its real end
130 * time yet).
131 *
132 * @param quark
133 * The quark of the attribute
134 * @return An interval representing the current state (but whose end time is
135 * meaningless)
136 * @throws AttributeNotFoundException
137 * If the quark is invalid
138 */
139 public ITmfStateInterval getOngoingInterval(int quark) throws AttributeNotFoundException {
140 checkValidAttribute(quark);
141 return new TmfStateInterval(ongoingStateStartTimes.get(quark), -1, quark,
142 ongoingStateInfo.get(quark));
143 }
144
145 private void checkValidAttribute(int quark) throws AttributeNotFoundException {
146 if (quark > ongoingStateInfo.size() - 1 || quark < 0) {
147 throw new AttributeNotFoundException();
148 }
149 }
150
151 /**
152 * More advanced version of {@link #changeOngoingStateValue}. Replaces the
153 * complete ongoingStateInfo in one go, and updates the
154 * ongoingStateStartTimes and #stateValuesTypes accordingly. BE VERY CAREFUL
155 * WITH THIS!
156 *
157 * @param newStateIntervals
158 * The List of intervals that will represent the new
159 * "ongoing state". Their end times don't matter, we will only
160 * check their value and start times.
161 */
162 public synchronized void replaceOngoingState(List<ITmfStateInterval> newStateIntervals) {
163 int size = newStateIntervals.size();
164 ongoingStateInfo = new ArrayList<>(size);
165 ongoingStateStartTimes = new ArrayList<>(size);
166 stateValueTypes = new ArrayList<>(size);
167
168 for (ITmfStateInterval interval : newStateIntervals) {
169 ongoingStateInfo.add(interval.getStateValue());
170 ongoingStateStartTimes.add(interval.getStartTime());
171 stateValueTypes.add(interval.getStateValue().getType());
172 }
173 }
174
175 /**
176 * Add an "empty line" to both "ongoing..." vectors. This is needed so the
177 * Ongoing... tables can stay in sync with the number of attributes in the
178 * attribute tree, namely when we add sub-path attributes.
179 */
180 public synchronized void addEmptyEntry() {
181 /*
182 * Since this is a new attribute, we suppose it was in the "null state"
183 * since the beginning (so we can have intervals covering for all
184 * timestamps). A null interval will then get added at the first state
185 * change.
186 */
187 ongoingStateInfo.add(TmfStateValue.nullValue());
188 stateValueTypes.add(Type.NULL);
189
190 if (backend == null) {
191 ongoingStateStartTimes.add(0L);
192 } else {
193 ongoingStateStartTimes.add(backend.getStartTime());
194 }
195 }
196
197 /**
198 * Ask if the state information about attribute 'quark' at time 'time' is
199 * present in the Builder as it is right now. If it's not, it's either in
200 * the History Tree, or not in the system at all.
201 *
202 * Note that this method does not return the value itself (we don't even
203 * look for it, we can know by just looking at the timestamp)
204 *
205 * @param time
206 * The timestamp to look for
207 * @param quark
208 * The quark of the attribute to look for
209 * @return True if the value is present in the Transient State at this
210 * moment in time, false if it's not
211 */
212 public boolean hasInfoAboutStateOf(long time, int quark) {
213 return (this.isActive() && time >= ongoingStateStartTimes.get(quark));
214 }
215
216 /**
217 * Process a state change to be inserted in the history.
218 *
219 * @param eventTime
220 * The timestamp associated with this state change
221 * @param value
222 * The new StateValue associated to this attribute
223 * @param quark
224 * The quark of the attribute that is being modified
225 * @throws TimeRangeException
226 * If 'eventTime' is invalid
227 * @throws AttributeNotFoundException
228 * IF 'quark' does not represent an existing attribute
229 * @throws StateValueTypeException
230 * If the state value to be inserted is of a different type of
231 * what was inserted so far for this attribute.
232 */
233 public synchronized void processStateChange(long eventTime,
234 ITmfStateValue value, int quark) throws TimeRangeException,
235 AttributeNotFoundException, StateValueTypeException {
236 assert (this.isActive);
237
238 Type expectedSvType = stateValueTypes.get(quark);
239 checkValidAttribute(quark);
240
241 /*
242 * Make sure the state value type we're inserting is the same as the
243 * one registered for this attribute.
244 */
245 if (expectedSvType == Type.NULL) {
246 /*
247 * The value hasn't been used yet, set it to the value
248 * we're currently inserting (which might be null/-1 again).
249 */
250 stateValueTypes.set(quark, value.getType());
251 } else if ((value.getType() != Type.NULL) && (value.getType() != expectedSvType)) {
252 /*
253 * We authorize inserting null values in any type of attribute,
254 * but for every other types, it needs to match our expectations!
255 */
256 throw new StateValueTypeException();
257 }
258
259 /* Update the Transient State's lastestTime, if needed */
260 if (latestTime < eventTime) {
261 latestTime = eventTime;
262 }
263
264 if (ongoingStateInfo.get(quark).equals(value)) {
265 /*
266 * This is the case where the new value and the one already present
267 * in the Builder are the same. We do not need to create an
268 * interval, we'll just keep the current one going.
269 */
270 return;
271 }
272
273 if (backend != null && ongoingStateStartTimes.get(quark) < eventTime) {
274 /*
275 * These two conditions are necessary to create an interval and
276 * update ongoingStateInfo.
277 */
278 backend.insertPastState(ongoingStateStartTimes.get(quark),
279 eventTime - 1, /* End Time */
280 quark, /* attribute quark */
281 ongoingStateInfo.get(quark)); /* StateValue */
282
283 ongoingStateStartTimes.set(quark, eventTime);
284 }
285 ongoingStateInfo.set(quark, value);
286 return;
287 }
288
289 /**
290 * Run a "get state at time" query on the Transient State only.
291 *
292 * @param stateInfo
293 * The stateInfo object in which we will put our relevant
294 * information
295 * @param t
296 * The requested timestamp
297 */
298 public void doQuery(List<ITmfStateInterval> stateInfo, long t) {
299 ITmfStateInterval interval;
300
301 if (!this.isActive) {
302 return;
303 }
304 assert (stateInfo.size() == ongoingStateInfo.size());
305
306 for (int i = 0; i < ongoingStateInfo.size(); i++) {
307 /*
308 * We build a dummy interval with end time = -1 to put in the answer
309 * to the query.
310 */
311 if (this.hasInfoAboutStateOf(t, i)) {
312 interval = new TmfStateInterval(ongoingStateStartTimes.get(i), -1,
313 i, ongoingStateInfo.get(i));
314 stateInfo.set(i, interval);
315 }
316 }
317 }
318
319 /**
320 * Close off the Transient State, used for example when we are done reading
321 * a static trace file. All the information currently contained in it will
322 * be converted to intervals and "flushed" to the state history.
323 *
324 * @param endTime
325 * The timestamp to use as end time for the state history (since
326 * it may be different than the timestamp of the last state
327 * change)
328 */
329 public void closeTransientState(long endTime) {
330 assert (this.isActive);
331
332 for (int i = 0; i < ongoingStateInfo.size(); i++) {
333 if (ongoingStateStartTimes.get(i) > endTime) {
334 /*
335 * Handle the cases where trace end > timestamp of last state
336 * change. This can happen when inserting "future" changes.
337 */
338 continue;
339 }
340 try {
341 backend.insertPastState(ongoingStateStartTimes.get(i),
342 endTime, /* End Time */
343 i, /* attribute quark */
344 ongoingStateInfo.get(i)); /* StateValue */
345
346 } catch (TimeRangeException e) {
347 /*
348 * This shouldn't happen, since we control where the interval's
349 * start time comes from
350 */
351 throw new IllegalStateException(e);
352 }
353 }
354
355 ongoingStateInfo.clear();
356 ongoingStateStartTimes.clear();
357 this.isActive = false;
358 return;
359 }
360
361 /**
362 * Simply returns if this Transient State is currently being used or not
363 *
364 * @return True if this transient state is active
365 */
366 public boolean isActive() {
367 return this.isActive;
368 }
369
370 /**
371 * Mark this transient state as inactive
372 */
373 public void setInactive() {
374 isActive = false;
375 }
376
377 /**
378 * Debugging method that prints the contents of the transient state
379 *
380 * @param writer
381 * The writer to which the output should be written
382 */
383 public void debugPrint(PrintWriter writer) {
384 /* Only used for debugging, shouldn't be externalized */
385 writer.println("------------------------------"); //$NON-NLS-1$
386 writer.println("Info stored in the Builder:"); //$NON-NLS-1$
387 if (!this.isActive) {
388 writer.println("Builder is currently inactive"); //$NON-NLS-1$
389 writer.println('\n');
390 return;
391 }
392 writer.println("\nAttribute\tStateValue\tValid since time"); //$NON-NLS-1$
393 for (int i = 0; i < ongoingStateInfo.size(); i++) {
394 writer.format("%d\t\t", i); //$NON-NLS-1$
395 writer.print(ongoingStateInfo.get(i).toString() + "\t\t"); //$NON-NLS-1$
396 writer.println(ongoingStateStartTimes.get(i).toString());
397 }
398 writer.println('\n');
399 return;
400 }
401
402 }
This page took 0.0391550000000001 seconds and 6 git commands to generate.