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