1
/*******************************************************************************
2
* Copyright (c) 2012 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.tmf.core.exceptions.AttributeNotFoundException;
20
import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
21
import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
22
import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
23
import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
24
import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
25
import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
28
* The Transient State is used to build intervals from punctual state changes. It
29
* contains a "state info" vector similar to the "current state", except here we
30
* also record the start time of every state stored in it.
32
* We can then build StateInterval's, to be inserted in the State History when
33
* we detect state changes : the "start time" of the interval will be the
34
* recorded time we have here, and the "end time" will be the timestamp of the
35
* new state-changing event we just read.
40
class TransientState {
42
/* Indicates where to insert state changes that we generate */
43
private final IStateHistoryBackend backend;
45
private boolean isActive;
46
private long latestTime;
48
private ArrayList<ITmfStateValue> ongoingStateInfo;
49
private final ArrayList<Long> ongoingStateStartTimes;
50
private final ArrayList<Byte> stateValueTypes;
52
TransientState(IStateHistoryBackend backend) {
53
this.backend = backend;
55
ongoingStateInfo = new ArrayList<ITmfStateValue>();
56
ongoingStateStartTimes = new ArrayList<Long>();
57
stateValueTypes = new ArrayList<Byte>();
59
if (backend != null) {
60
latestTime = backend.getStartTime();
66
long getLatestTime() {
70
ITmfStateValue getOngoingStateValue(int index)
71
throws AttributeNotFoundException {
73
checkValidAttribute(index);
74
return ongoingStateInfo.get(index);
77
void changeOngoingStateValue(int index, ITmfStateValue newValue)
78
throws AttributeNotFoundException {
80
checkValidAttribute(index);
81
ongoingStateInfo.set(index, newValue);
85
* Return the "ongoing" value for a given attribute as a dummy interval
86
* whose end time = -1 (since we don't know its real end time yet).
89
* @throws AttributeNotFoundException
91
ITmfStateInterval getOngoingInterval(int quark)
92
throws AttributeNotFoundException {
94
checkValidAttribute(quark);
95
return new TmfStateInterval(ongoingStateStartTimes.get(quark), -1, quark,
96
ongoingStateInfo.get(quark));
99
private void checkValidAttribute(int quark)
100
throws AttributeNotFoundException {
102
if (quark > ongoingStateInfo.size() - 1 || quark < 0) {
103
throw new AttributeNotFoundException();
108
* Batch method of changeOngoingStateValue(), updates the complete
109
* ongoingStateInfo in one go. BE VERY CAREFUL WITH THIS! Especially with
110
* the sizes of both arrays.
112
* Note that the new ongoingStateInfo will be a shallow copy of
113
* newStateInfo, so that last one must be already instantiated and all.
115
* @param newStateInfo
116
* The List of StateValues to replace the old ongoingStateInfo
119
void changeOngoingStateInfo(ArrayList<ITmfStateValue> newStateInfo) {
120
this.ongoingStateInfo = newStateInfo;
124
* Add an "empty line" to both "ongoing..." vectors. This is needed so the
125
* Ongoing... tables can stay in sync with the number of attributes in the
126
* attribute tree, namely when we add sub-path attributes.
128
synchronized void addEmptyEntry() {
130
* Since this is a new attribute, we suppose it was in the "null state"
131
* since the beginning (so we can have intervals covering for all
132
* timestamps). A null interval will then get added at the first state
135
ongoingStateInfo.add(TmfStateValue.nullValue());
136
stateValueTypes.add((byte) -1);
138
if (backend == null) {
139
ongoingStateStartTimes.add(0L);
141
ongoingStateStartTimes.add(backend.getStartTime());
146
* Ask if the state information about attribute 'quark' at time 'time' is
147
* present in the Builder as it is right now. If it's not, it's either in
148
* the History Tree, or not in the system at all.
150
* Note that this method does not return the value itself (we don't even
151
* look for it, we can know by just looking at the timestamp)
154
* The timestamp to look for
156
* The quark of the attribute to look for
157
* @return True if the value is present in the Transient State at this
158
* moment in time, false if it's not
160
boolean hasInfoAboutStateOf(long time, int quark) {
161
return (this.isActive() && time >= ongoingStateStartTimes.get(quark));
165
* This is the lower-level method that will be called by the
166
* StateHistorySystem (with already-built StateValues and timestamps)
169
* The index in the vectors (== the quark of the attribute)
171
* The new StateValue associated to this attribute
173
* The timestamp associated with this state change
174
* @throws TimeRangeException
175
* @throws AttributeNotFoundException
176
* @throws StateValueTypeException
178
synchronized void processStateChange(long eventTime,
179
ITmfStateValue value, int index) throws TimeRangeException,
180
AttributeNotFoundException, StateValueTypeException {
181
assert (this.isActive);
183
byte expectedSvType = stateValueTypes.get(index);
184
checkValidAttribute(index);
187
* Make sure the state value type we're inserting is the same as the
188
* one registered for this attribute.
190
if (expectedSvType == -1) {
192
* The value hasn't been used yet, set it to the value
193
* we're currently inserting (which might be null/-1 again).
195
stateValueTypes.set(index, value.getType());
196
} else if ((value.getType() != -1) && (value.getType() != expectedSvType)) {
198
* We authorize inserting null values in any type of attribute,
199
* but for every other types, it needs to match our expectations!
201
throw new StateValueTypeException();
204
/* Update the Transient State's lastestTime, if needed */
205
if (latestTime < eventTime) {
206
latestTime = eventTime;
209
if (ongoingStateInfo.get(index).equals(value)) {
211
* This is the case where the new value and the one already present
212
* in the Builder are the same. We do not need to create an
213
* interval, we'll just keep the current one going.
218
if (backend != null && ongoingStateStartTimes.get(index) < eventTime) {
220
* These two conditions are necessary to create an interval and
221
* update ongoingStateInfo.
223
backend.insertPastState(ongoingStateStartTimes.get(index),
224
eventTime - 1, /* End Time */
225
index, /* attribute quark */
226
ongoingStateInfo.get(index)); /* StateValue */
228
ongoingStateStartTimes.set(index, eventTime);
230
ongoingStateInfo.set(index, value);
235
* Run a "get state at time" query on the Transient State only.
238
* The stateInfo object in which we will put our relevant
241
* The requested timestamp
243
void doQuery(List<ITmfStateInterval> stateInfo, long t) {
244
ITmfStateInterval interval;
246
if (!this.isActive) {
249
assert (stateInfo.size() == ongoingStateInfo.size());
251
for (int i = 0; i < ongoingStateInfo.size(); i++) {
253
* We build a dummy interval with end time = -1 to put in the answer
256
if (this.hasInfoAboutStateOf(t, i)) {
257
interval = new TmfStateInterval(ongoingStateStartTimes.get(i), -1,
258
i, ongoingStateInfo.get(i));
259
stateInfo.set(i, interval);
265
* Close off the Transient State, used for example when we are done reading a
266
* static trace file. All the information currently contained in it will be
267
* converted to intervals and "flushed" to the State History.
269
void closeTransientState(long endTime) {
270
assert (this.isActive);
272
for (int i = 0; i < ongoingStateInfo.size(); i++) {
273
if (ongoingStateStartTimes.get(i) == endTime) {
275
* Handle this rare case where trace end == timetamp of last
281
backend.insertPastState(ongoingStateStartTimes.get(i),
282
endTime, /* End Time */
283
i, /* attribute quark */
284
ongoingStateInfo.get(i)); /* StateValue */
286
} catch (TimeRangeException e) {
288
* This shouldn't happen, since we control where the interval's
289
* start time comes from
295
ongoingStateInfo.clear();
296
ongoingStateStartTimes.clear();
297
this.isActive = false;
302
* Simply returns if this Transient State is currently being used or not
307
return this.isActive;
315
* Debugging method that prints the contents of both 'ongoing...' vectors
319
void debugPrint(PrintWriter writer) {
320
/* Only used for debugging, shouldn't be externalized */
321
writer.println("------------------------------"); //$NON-NLS-1$
322
writer.println("Info stored in the Builder:"); //$NON-NLS-1$
323
if (!this.isActive) {
324
writer.println("Builder is currently inactive"); //$NON-NLS-1$
325
writer.println('\n');
328
writer.println("\nAttribute\tStateValue\tValid since time"); //$NON-NLS-1$
329
for (int i = 0; i < ongoingStateInfo.size(); i++) {
330
writer.format("%d\t\t", i); //$NON-NLS-1$
331
writer.print(ongoingStateInfo.get(i).toString() + "\t\t"); //$NON-NLS-1$
332
writer.println(ongoingStateStartTimes.get(i).toString());
334
writer.println('\n');
b'\\ No newline at end of file'