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