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