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