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