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
.tmf
.core
.statesystem
;
16 import java
.io
.FileInputStream
;
17 import java
.io
.IOException
;
18 import java
.io
.PrintWriter
;
19 import java
.util
.ArrayList
;
20 import java
.util
.List
;
22 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.helpers
.IStateHistoryBackend
;
26 * This is the extension of the StateSystem, which will save the state intervals
27 * that are created from the transient state (instead of discarding them, like a
28 * simple StateSystem would do).
30 * This allows the user to then run queries at past timestamps.
32 * DON'T FORGET to call .closeHistory() when you are done inserting intervals,
33 * or the storage backend will have no way of knowing it can close and write
34 * itself to disk, and its thread will keep running.
39 public class StateHistorySystem
extends StateSystem
{
42 * Inherited from StateSystem
44 * protected ArrayList<AttributeTreeNode> attributeList; protected
45 * TransientState transState; protected CurrentState curState;
48 private final IStateHistoryBackend backend
;
51 * This the container that will hold the result of full queries obtained
52 * with loadStateAtTime()
54 private ArrayList
<ITmfStateInterval
> currentStateInfo
;
60 * The "state history storage" backend to use.
62 * Put true if this is a new history started from scratch. It is
63 * used to tell the state system where to get its attribute tree.
66 public StateHistorySystem(IStateHistoryBackend backend
, boolean newFile
)
68 this.backend
= backend
;
69 transState
= new TransientState(backend
);
70 currentStateInfo
= new ArrayList
<ITmfStateInterval
>();
73 attributeTree
= new AttributeTree(this);
75 /* We're opening an existing file */
76 FileInputStream attributeTreeInput
= backend
.supplyAttributeTreeReader();
77 this.attributeTree
= new AttributeTree(this, attributeTreeInput
);
78 transState
.setInactive();
82 public IStateHistoryBackend
getHistoryBackend() {
87 * Method to close off the History Provider. This happens for example when
88 * we are done reading an off-line trace. First we close the TransientState,
89 * commit it to the Provider, mark it as inactive, then we write the
90 * Attribute Tree somewhere so we can reopen it later.
93 * The requested End Time of the history, since it could be
94 * bigger than the timestamp of the last event or state change we
95 * have seen. All "ongoing" states will be extended until this
97 * @throws TimeRangeException
98 * If the passed endTime doesn't make sense (for example, if
99 * it's earlier than the latest time) and the backend doesn't
100 * know how to handle it.
102 public void closeHistory(long endTime
) throws TimeRangeException
{
103 File attributeTreeFile
;
104 long attributeTreeFilePos
;
105 long realEndTime
= endTime
;
107 if (realEndTime
< backend
.getEndTime()) {
109 * This can happen (empty nodes pushing the border further, etc.)
110 * but shouldn't be too big of a deal.
112 realEndTime
= backend
.getEndTime();
114 transState
.closeTransientState(realEndTime
);
115 backend
.finishedBuilding(realEndTime
);
117 attributeTreeFile
= backend
.supplyAttributeTreeWriterFile();
118 attributeTreeFilePos
= backend
.supplyAttributeTreeWriterFilePosition();
119 if (attributeTreeFile
!= null) {
121 * If null was returned, we simply won't save the attribute tree,
124 attributeTree
.writeSelf(attributeTreeFile
, attributeTreeFilePos
);
129 * @name External query methods
133 * Load the state information at time 't' as the Current State. You can then
134 * use the queryState() method to query the value of different attributes,
135 * as they were at time 't'.
137 * On average if you need around 10 or more queries for the same timestamps,
138 * use this. If you need less than 10 (for example, running many queries for
139 * the same attributes but at different timestamps), you might be better
140 * using the querySingleState() methods instead.
143 * We will recreate the state information to what it was at time
145 * @throws TimeRangeException
147 public synchronized void loadStateAtTime(long t
) throws TimeRangeException
{
148 /* Empty the currentStateInfo */
149 currentStateInfo
= new ArrayList
<ITmfStateInterval
>(
150 attributeTree
.getNbAttributes());
151 for (int i
= 0; i
< attributeTree
.getNbAttributes(); i
++) {
152 currentStateInfo
.add(null);
155 backend
.doQuery(currentStateInfo
, t
);
157 if (transState
.isActive()) {
158 transState
.doQuery(currentStateInfo
, t
);
160 // We should have previously inserted an interval for every attribute
161 // for all possible timestamps (and those could contain 'nullValues').
162 // There should be no 'null' objects at this point.
163 for (ITmfStateInterval interval
: currentStateInfo
) {
164 assert (interval
!= null);
169 * Once we have set up the "current state" using loadStateAtTime(), we can
170 * now run queries to get the state of individual attributes at the
171 * previously loaded timestamp.
173 * @param attributeQuark
174 * The quark of attribute for which we want the state.
175 * @return The StateInterval object matching this timestamp/attribute pair.
176 * @throws AttributeNotFoundException
178 public ITmfStateInterval
queryState(int attributeQuark
) {
179 return currentStateInfo
.get(attributeQuark
);
183 * Alternative, singular version of the "queryState" method. This one does
184 * not update the whole stateInfo vector, like loadStateAtTimes does. It
185 * only searches for one specific entry in the state history.
187 * It should be used when you only want very few entries, instead of the
188 * whole state (or many entries, but all at different timestamps). If you do
189 * request many entries all at the same time, you should use the
190 * conventional loadStateAtTime() + queryState() method.
193 * The timestamp at which we want the state
194 * @param attributeQuark
195 * Which attribute we want to get the state of
196 * @return The StateInterval representing the state
197 * @throws TimeRangeException
198 * @throws AttributeNotFoundException
200 public ITmfStateInterval
querySingleState(long t
, int attributeQuark
)
201 throws AttributeNotFoundException
, TimeRangeException
{
202 ITmfStateInterval ret
;
204 if (transState
.hasInfoAboutStateOf(t
, attributeQuark
)) {
205 ret
= transState
.getOngoingInterval(attributeQuark
);
207 ret
= backend
.doSingularQuery(t
, attributeQuark
);
209 assert (ret
!= null);
214 * Return a list of state intervals, containing the "history" of a given
215 * attribute between timestamps t1 and t2. The list will be ordered by
218 * @param attributeQuark
219 * Which attribute this query is interested in
221 * Start time of the range query
223 * End time of the query
224 * @return The List of state intervals that happened between t1 and t2
225 * @throws TimeRangeException
226 * @throws AttributeNotFoundException
228 public List
<ITmfStateInterval
> queryHistoryRange(int attributeQuark
, long t1
,
229 long t2
) throws TimeRangeException
, AttributeNotFoundException
{
231 List
<ITmfStateInterval
> intervals
= new ArrayList
<ITmfStateInterval
>();
232 ITmfStateInterval currentInterval
;
235 /* Get the initial state at time T1 */
236 currentInterval
= querySingleState(t1
, attributeQuark
);
237 intervals
.add(currentInterval
);
239 /* Get the following state changes */
240 ts
= currentInterval
.getEndTime();
241 while (ts
!= -1 && ts
<= t2
) {
242 ts
++; /* To "jump over" to the next state in the history */
243 currentInterval
= querySingleState(ts
, attributeQuark
);
244 intervals
.add(currentInterval
);
245 ts
= currentInterval
.getEndTime();
251 * @name Debugging methods
255 * Print out the contents of the inner structures to the selected
259 public void debugPrint(PrintWriter writer
) {
260 /* Only used for debugging, shouldn't be externalized */
261 writer
.println("------------------------------"); //$NON-NLS-1$
262 writer
.println("Current State Info vector:\n"); //$NON-NLS-1$
263 for (int i
= 0; i
< currentStateInfo
.size(); i
++) {
264 writer
.print(i
+ "\t\t"); //$NON-NLS-1$
265 if (currentStateInfo
.get(i
) == null) {
266 writer
.println("null"); //$NON-NLS-1$
268 writer
.println(currentStateInfo
.get(i
).toString());
271 writer
.println('\n');
273 /* Print the other inner containers */
274 super.debugPrint(writer
);
275 backend
.debugPrint(writer
);