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. It
31 * contains a "state info" vector similar to the "current state", except here we
32 * also record the start time of every state stored in it.
34 * We can then build StateInterval's, to be inserted in the State History when
35 * we detect state changes : the "start time" of the interval will be the
36 * recorded time we have here, and the "end time" will be the timestamp of the
37 * new state-changing event we just read.
42 class TransientState
{
44 /* Indicates where to insert state changes that we generate */
45 private final IStateHistoryBackend backend
;
47 private boolean isActive
;
48 private long latestTime
;
50 private List
<ITmfStateValue
> ongoingStateInfo
;
51 private List
<Long
> ongoingStateStartTimes
;
52 private List
<Type
> stateValueTypes
;
54 TransientState(IStateHistoryBackend backend
) {
55 this.backend
= backend
;
57 ongoingStateInfo
= new ArrayList
<>();
58 ongoingStateStartTimes
= new ArrayList
<>();
59 stateValueTypes
= new ArrayList
<>();
61 if (backend
!= null) {
62 latestTime
= backend
.getStartTime();
68 long getLatestTime() {
72 ITmfStateValue
getOngoingStateValue(int index
) throws AttributeNotFoundException
{
73 checkValidAttribute(index
);
74 return ongoingStateInfo
.get(index
);
77 long getOngoingStartTime(int index
) throws AttributeNotFoundException
{
78 checkValidAttribute(index
);
79 return ongoingStateStartTimes
.get(index
);
82 void changeOngoingStateValue(int index
, ITmfStateValue newValue
)
83 throws AttributeNotFoundException
{
84 checkValidAttribute(index
);
85 ongoingStateInfo
.set(index
, newValue
);
89 * Return the "ongoing" value for a given attribute as a dummy interval
90 * whose end time = -1 (since we don't know its real end time yet).
93 * @throws AttributeNotFoundException
95 ITmfStateInterval
getOngoingInterval(int quark
) throws AttributeNotFoundException
{
96 checkValidAttribute(quark
);
97 return new TmfStateInterval(ongoingStateStartTimes
.get(quark
), -1, quark
,
98 ongoingStateInfo
.get(quark
));
101 private void checkValidAttribute(int quark
) throws AttributeNotFoundException
{
102 if (quark
> ongoingStateInfo
.size() - 1 || quark
< 0) {
103 throw new AttributeNotFoundException();
108 * More advanced version of {@link #changeOngoingStateValue}. Replaces the
109 * complete {@link #ongoingStateInfo} in one go, and updates the
110 * {@link #ongoingStateStartTimes} and {@link #stateValuesTypes}
111 * accordingly. BE VERY CAREFUL WITH THIS!
113 * @param newStateIntervals
114 * The List of intervals that will represent the new
115 * "ongoing state". Their end times don't matter, we will only
116 * check their value and start times.
118 synchronized void replaceOngoingState(List
<ITmfStateInterval
> newStateIntervals
) {
119 int size
= newStateIntervals
.size();
120 ongoingStateInfo
= new ArrayList
<>(size
);
121 ongoingStateStartTimes
= new ArrayList
<>(size
);
122 stateValueTypes
= new ArrayList
<>(size
);
124 for (ITmfStateInterval interval
: newStateIntervals
) {
125 ongoingStateInfo
.add(interval
.getStateValue());
126 ongoingStateStartTimes
.add(interval
.getStartTime());
127 stateValueTypes
.add(interval
.getStateValue().getType());
132 * Add an "empty line" to both "ongoing..." vectors. This is needed so the
133 * Ongoing... tables can stay in sync with the number of attributes in the
134 * attribute tree, namely when we add sub-path attributes.
136 synchronized void addEmptyEntry() {
138 * Since this is a new attribute, we suppose it was in the "null state"
139 * since the beginning (so we can have intervals covering for all
140 * timestamps). A null interval will then get added at the first state
143 ongoingStateInfo
.add(TmfStateValue
.nullValue());
144 stateValueTypes
.add(Type
.NULL
);
146 if (backend
== null) {
147 ongoingStateStartTimes
.add(0L);
149 ongoingStateStartTimes
.add(backend
.getStartTime());
154 * Ask if the state information about attribute 'quark' at time 'time' is
155 * present in the Builder as it is right now. If it's not, it's either in
156 * the History Tree, or not in the system at all.
158 * Note that this method does not return the value itself (we don't even
159 * look for it, we can know by just looking at the timestamp)
162 * The timestamp to look for
164 * The quark of the attribute to look for
165 * @return True if the value is present in the Transient State at this
166 * moment in time, false if it's not
168 boolean hasInfoAboutStateOf(long time
, int quark
) {
169 return (this.isActive() && time
>= ongoingStateStartTimes
.get(quark
));
173 * This is the lower-level method that will be called by the
174 * StateHistorySystem (with already-built StateValues and timestamps)
177 * The index in the vectors (== the quark of the attribute)
179 * The new StateValue associated to this attribute
181 * The timestamp associated with this state change
182 * @throws TimeRangeException
183 * @throws AttributeNotFoundException
184 * @throws StateValueTypeException
186 synchronized void processStateChange(long eventTime
,
187 ITmfStateValue value
, int index
) throws TimeRangeException
,
188 AttributeNotFoundException
, StateValueTypeException
{
189 assert (this.isActive
);
191 Type expectedSvType
= stateValueTypes
.get(index
);
192 checkValidAttribute(index
);
195 * Make sure the state value type we're inserting is the same as the
196 * one registered for this attribute.
198 if (expectedSvType
== Type
.NULL
) {
200 * The value hasn't been used yet, set it to the value
201 * we're currently inserting (which might be null/-1 again).
203 stateValueTypes
.set(index
, value
.getType());
204 } else if ((value
.getType() != Type
.NULL
) && (value
.getType() != expectedSvType
)) {
206 * We authorize inserting null values in any type of attribute,
207 * but for every other types, it needs to match our expectations!
209 throw new StateValueTypeException();
212 /* Update the Transient State's lastestTime, if needed */
213 if (latestTime
< eventTime
) {
214 latestTime
= eventTime
;
217 if (ongoingStateInfo
.get(index
).equals(value
)) {
219 * This is the case where the new value and the one already present
220 * in the Builder are the same. We do not need to create an
221 * interval, we'll just keep the current one going.
226 if (backend
!= null && ongoingStateStartTimes
.get(index
) < eventTime
) {
228 * These two conditions are necessary to create an interval and
229 * update ongoingStateInfo.
231 backend
.insertPastState(ongoingStateStartTimes
.get(index
),
232 eventTime
- 1, /* End Time */
233 index
, /* attribute quark */
234 ongoingStateInfo
.get(index
)); /* StateValue */
236 ongoingStateStartTimes
.set(index
, eventTime
);
238 ongoingStateInfo
.set(index
, value
);
243 * Run a "get state at time" query on the Transient State only.
246 * The stateInfo object in which we will put our relevant
249 * The requested timestamp
251 void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
) {
252 ITmfStateInterval interval
;
254 if (!this.isActive
) {
257 assert (stateInfo
.size() == ongoingStateInfo
.size());
259 for (int i
= 0; i
< ongoingStateInfo
.size(); i
++) {
261 * We build a dummy interval with end time = -1 to put in the answer
264 if (this.hasInfoAboutStateOf(t
, i
)) {
265 interval
= new TmfStateInterval(ongoingStateStartTimes
.get(i
), -1,
266 i
, ongoingStateInfo
.get(i
));
267 stateInfo
.set(i
, interval
);
273 * Close off the Transient State, used for example when we are done reading a
274 * static trace file. All the information currently contained in it will be
275 * converted to intervals and "flushed" to the State History.
277 void closeTransientState(long endTime
) {
278 assert (this.isActive
);
280 for (int i
= 0; i
< ongoingStateInfo
.size(); i
++) {
281 if (ongoingStateStartTimes
.get(i
) > endTime
) {
283 * Handle the cases where trace end > timestamp of last state
284 * change. This can happen when inserting "future" changes.
289 backend
.insertPastState(ongoingStateStartTimes
.get(i
),
290 endTime
, /* End Time */
291 i
, /* attribute quark */
292 ongoingStateInfo
.get(i
)); /* StateValue */
294 } catch (TimeRangeException e
) {
296 * This shouldn't happen, since we control where the interval's
297 * start time comes from
299 throw new IllegalStateException(e
);
303 ongoingStateInfo
.clear();
304 ongoingStateStartTimes
.clear();
305 this.isActive
= false;
310 * Simply returns if this Transient State is currently being used or not
315 return this.isActive
;
323 * Debugging method that prints the contents of both 'ongoing...' vectors
327 void debugPrint(PrintWriter writer
) {
328 /* Only used for debugging, shouldn't be externalized */
329 writer
.println("------------------------------"); //$NON-NLS-1$
330 writer
.println("Info stored in the Builder:"); //$NON-NLS-1$
331 if (!this.isActive
) {
332 writer
.println("Builder is currently inactive"); //$NON-NLS-1$
333 writer
.println('\n');
336 writer
.println("\nAttribute\tStateValue\tValid since time"); //$NON-NLS-1$
337 for (int i
= 0; i
< ongoingStateInfo
.size(); i
++) {
338 writer
.format("%d\t\t", i
); //$NON-NLS-1$
339 writer
.print(ongoingStateInfo
.get(i
).toString() + "\t\t"); //$NON-NLS-1$
340 writer
.println(ongoingStateStartTimes
.get(i
).toString());
342 writer
.println('\n');