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>
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
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.tmf
.core
.statesystem
;
15 import java
.io
.PrintWriter
;
16 import java
.util
.ArrayList
;
17 import java
.util
.List
;
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 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
.Type
;
30 * The Transient State is used to build intervals from punctual state changes.
31 * It contains a "state info" vector similar to the "current state", except here
32 * we also record the start time of every state stored in it.
34 * We can then build {@link ITmfStateInterval}'s, to be inserted in a
35 * {@link IStateHistoryBackend} when we detect state changes : the "start time"
36 * of the interval will be the recorded time we have here, and the "end time"
37 * will be the timestamp of the new state-changing event we just read.
39 * @author Alexandre Montplaisir
41 public class TransientState
{
43 /* Indicates where to insert state changes that we generate */
44 private final IStateHistoryBackend backend
;
46 private boolean isActive
;
47 private long latestTime
;
49 private List
<ITmfStateValue
> ongoingStateInfo
;
50 private List
<Long
> ongoingStateStartTimes
;
51 private List
<Type
> stateValueTypes
;
57 * The back-end in which to insert the generated state intervals
59 public TransientState(IStateHistoryBackend backend
) {
60 this.backend
= backend
;
62 ongoingStateInfo
= new ArrayList
<>();
63 ongoingStateStartTimes
= new ArrayList
<>();
64 stateValueTypes
= new ArrayList
<>();
66 if (backend
!= null) {
67 latestTime
= backend
.getStartTime();
74 * Get the latest time we have seen so far.
76 * @return The latest time seen in the transient state
78 public long getLatestTime() {
83 * Retrieve the ongoing state value for a given index (attribute quark).
86 * The quark of the attribute to look for
87 * @return The corresponding state value
88 * @throws AttributeNotFoundException
89 * If the quark is invalid
91 public ITmfStateValue
getOngoingStateValue(int quark
) throws AttributeNotFoundException
{
92 checkValidAttribute(quark
);
93 return ongoingStateInfo
.get(quark
);
97 * Retrieve the start time of the state in which the given attribute is in.
100 * The quark of the attribute to look for
101 * @return The start time of the current state for this attribute
102 * @throws AttributeNotFoundException
103 * If the quark is invalid
105 public long getOngoingStartTime(int quark
) throws AttributeNotFoundException
{
106 checkValidAttribute(quark
);
107 return ongoingStateStartTimes
.get(quark
);
111 * Modify the current state for a given attribute. This will not update the
112 * "ongoing state start time" in any way, so be careful when using this.
115 * The quark of the attribute to modify
117 * The state value the attribute should have
118 * @throws AttributeNotFoundException
119 * If the quark is invalid
121 public void changeOngoingStateValue(int quark
, ITmfStateValue newValue
)
122 throws AttributeNotFoundException
{
123 checkValidAttribute(quark
);
124 ongoingStateInfo
.set(quark
, newValue
);
128 * Convenience method to return the "ongoing" value for a given attribute as
129 * a dummy interval whose end time = -1 (since we don't know its real end
133 * The quark of the attribute
134 * @return An interval representing the current state (but whose end time is
136 * @throws AttributeNotFoundException
137 * If the quark is invalid
139 public ITmfStateInterval
getOngoingInterval(int quark
) throws AttributeNotFoundException
{
140 checkValidAttribute(quark
);
141 return new TmfStateInterval(ongoingStateStartTimes
.get(quark
), -1, quark
,
142 ongoingStateInfo
.get(quark
));
145 private void checkValidAttribute(int quark
) throws AttributeNotFoundException
{
146 if (quark
> ongoingStateInfo
.size() - 1 || quark
< 0) {
147 throw new AttributeNotFoundException();
152 * More advanced version of {@link #changeOngoingStateValue}. Replaces the
153 * complete ongoingStateInfo in one go, and updates the
154 * ongoingStateStartTimes and #stateValuesTypes accordingly. BE VERY CAREFUL
157 * @param newStateIntervals
158 * The List of intervals that will represent the new
159 * "ongoing state". Their end times don't matter, we will only
160 * check their value and start times.
162 public synchronized void replaceOngoingState(List
<ITmfStateInterval
> newStateIntervals
) {
163 int size
= newStateIntervals
.size();
164 ongoingStateInfo
= new ArrayList
<>(size
);
165 ongoingStateStartTimes
= new ArrayList
<>(size
);
166 stateValueTypes
= new ArrayList
<>(size
);
168 for (ITmfStateInterval interval
: newStateIntervals
) {
169 ongoingStateInfo
.add(interval
.getStateValue());
170 ongoingStateStartTimes
.add(interval
.getStartTime());
171 stateValueTypes
.add(interval
.getStateValue().getType());
176 * Add an "empty line" to both "ongoing..." vectors. This is needed so the
177 * Ongoing... tables can stay in sync with the number of attributes in the
178 * attribute tree, namely when we add sub-path attributes.
180 public synchronized void addEmptyEntry() {
182 * Since this is a new attribute, we suppose it was in the "null state"
183 * since the beginning (so we can have intervals covering for all
184 * timestamps). A null interval will then get added at the first state
187 ongoingStateInfo
.add(TmfStateValue
.nullValue());
188 stateValueTypes
.add(Type
.NULL
);
190 if (backend
== null) {
191 ongoingStateStartTimes
.add(0L);
193 ongoingStateStartTimes
.add(backend
.getStartTime());
198 * Ask if the state information about attribute 'quark' at time 'time' is
199 * present in the Builder as it is right now. If it's not, it's either in
200 * the History Tree, or not in the system at all.
202 * Note that this method does not return the value itself (we don't even
203 * look for it, we can know by just looking at the timestamp)
206 * The timestamp to look for
208 * The quark of the attribute to look for
209 * @return True if the value is present in the Transient State at this
210 * moment in time, false if it's not
212 public boolean hasInfoAboutStateOf(long time
, int quark
) {
213 return (this.isActive() && time
>= ongoingStateStartTimes
.get(quark
));
217 * Process a state change to be inserted in the history.
220 * The timestamp associated with this state change
222 * The new StateValue associated to this attribute
224 * The quark of the attribute that is being modified
225 * @throws TimeRangeException
226 * If 'eventTime' is invalid
227 * @throws AttributeNotFoundException
228 * IF 'quark' does not represent an existing attribute
229 * @throws StateValueTypeException
230 * If the state value to be inserted is of a different type of
231 * what was inserted so far for this attribute.
233 public synchronized void processStateChange(long eventTime
,
234 ITmfStateValue value
, int quark
) throws TimeRangeException
,
235 AttributeNotFoundException
, StateValueTypeException
{
236 assert (this.isActive
);
238 Type expectedSvType
= stateValueTypes
.get(quark
);
239 checkValidAttribute(quark
);
242 * Make sure the state value type we're inserting is the same as the
243 * one registered for this attribute.
245 if (expectedSvType
== Type
.NULL
) {
247 * The value hasn't been used yet, set it to the value
248 * we're currently inserting (which might be null/-1 again).
250 stateValueTypes
.set(quark
, value
.getType());
251 } else if ((value
.getType() != Type
.NULL
) && (value
.getType() != expectedSvType
)) {
253 * We authorize inserting null values in any type of attribute,
254 * but for every other types, it needs to match our expectations!
256 throw new StateValueTypeException();
259 /* Update the Transient State's lastestTime, if needed */
260 if (latestTime
< eventTime
) {
261 latestTime
= eventTime
;
264 if (ongoingStateInfo
.get(quark
).equals(value
)) {
266 * This is the case where the new value and the one already present
267 * in the Builder are the same. We do not need to create an
268 * interval, we'll just keep the current one going.
273 if (backend
!= null && ongoingStateStartTimes
.get(quark
) < eventTime
) {
275 * These two conditions are necessary to create an interval and
276 * update ongoingStateInfo.
278 backend
.insertPastState(ongoingStateStartTimes
.get(quark
),
279 eventTime
- 1, /* End Time */
280 quark
, /* attribute quark */
281 ongoingStateInfo
.get(quark
)); /* StateValue */
283 ongoingStateStartTimes
.set(quark
, eventTime
);
285 ongoingStateInfo
.set(quark
, value
);
290 * Run a "get state at time" query on the Transient State only.
293 * The stateInfo object in which we will put our relevant
296 * The requested timestamp
298 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
) {
299 ITmfStateInterval interval
;
301 if (!this.isActive
) {
304 assert (stateInfo
.size() == ongoingStateInfo
.size());
306 for (int i
= 0; i
< ongoingStateInfo
.size(); i
++) {
308 * We build a dummy interval with end time = -1 to put in the answer
311 if (this.hasInfoAboutStateOf(t
, i
)) {
312 interval
= new TmfStateInterval(ongoingStateStartTimes
.get(i
), -1,
313 i
, ongoingStateInfo
.get(i
));
314 stateInfo
.set(i
, interval
);
320 * Close off the Transient State, used for example when we are done reading
321 * a static trace file. All the information currently contained in it will
322 * be converted to intervals and "flushed" to the state history.
325 * The timestamp to use as end time for the state history (since
326 * it may be different than the timestamp of the last state
329 public void closeTransientState(long endTime
) {
330 assert (this.isActive
);
332 for (int i
= 0; i
< ongoingStateInfo
.size(); i
++) {
333 if (ongoingStateStartTimes
.get(i
) > endTime
) {
335 * Handle the cases where trace end > timestamp of last state
336 * change. This can happen when inserting "future" changes.
341 backend
.insertPastState(ongoingStateStartTimes
.get(i
),
342 endTime
, /* End Time */
343 i
, /* attribute quark */
344 ongoingStateInfo
.get(i
)); /* StateValue */
346 } catch (TimeRangeException e
) {
348 * This shouldn't happen, since we control where the interval's
349 * start time comes from
351 throw new IllegalStateException(e
);
355 ongoingStateInfo
.clear();
356 ongoingStateStartTimes
.clear();
357 this.isActive
= false;
362 * Simply returns if this Transient State is currently being used or not
364 * @return True if this transient state is active
366 public boolean isActive() {
367 return this.isActive
;
371 * Mark this transient state as inactive
373 public void setInactive() {
378 * Debugging method that prints the contents of the transient state
381 * The writer to which the output should be written
383 public void debugPrint(PrintWriter writer
) {
384 /* Only used for debugging, shouldn't be externalized */
385 writer
.println("------------------------------"); //$NON-NLS-1$
386 writer
.println("Info stored in the Builder:"); //$NON-NLS-1$
387 if (!this.isActive
) {
388 writer
.println("Builder is currently inactive"); //$NON-NLS-1$
389 writer
.println('\n');
392 writer
.println("\nAttribute\tStateValue\tValid since time"); //$NON-NLS-1$
393 for (int i
= 0; i
< ongoingStateInfo
.size(); i
++) {
394 writer
.format("%d\t\t", i
); //$NON-NLS-1$
395 writer
.print(ongoingStateInfo
.get(i
).toString() + "\t\t"); //$NON-NLS-1$
396 writer
.println(ongoingStateStartTimes
.get(i
).toString());
398 writer
.println('\n');