Merge Generic State System core part
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / statesystem / StateHistorySystem.java
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>
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 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.core.statesystem;
14
15 import java.io.File;
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;
21
22 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
23 import org.eclipse.linuxtools.tmf.core.statesystem.helpers.IStateHistoryBackend;
24
25 /**
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).
29 *
30 * This allows the user to then run queries at past timestamps.
31 *
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.
35 *
36 * @author alexmont
37 *
38 */
39 public class StateHistorySystem extends StateSystem {
40
41 /*
42 * Inherited from StateSystem
43 *
44 * protected ArrayList<AttributeTreeNode> attributeList; protected
45 * TransientState transState; protected CurrentState curState;
46 */
47
48 private final IStateHistoryBackend backend;
49
50 /*
51 * This the container that will hold the result of full queries obtained
52 * with loadStateAtTime()
53 */
54 private ArrayList<ITmfStateInterval> currentStateInfo;
55
56 /**
57 * General constructor
58 *
59 * @param backend
60 * The "state history storage" backend to use.
61 * @param newFile
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.
64 * @throws IOException
65 */
66 public StateHistorySystem(IStateHistoryBackend backend, boolean newFile)
67 throws IOException {
68 this.backend = backend;
69 transState = new TransientState(backend);
70 currentStateInfo = new ArrayList<ITmfStateInterval>();
71
72 if (newFile) {
73 attributeTree = new AttributeTree(this);
74 } else {
75 /* We're opening an existing file */
76 FileInputStream attributeTreeInput = backend.supplyAttributeTreeReader();
77 this.attributeTree = new AttributeTree(this, attributeTreeInput);
78 transState.setInactive();
79 }
80 }
81
82 public IStateHistoryBackend getHistoryBackend() {
83 return backend;
84 }
85
86 /**
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.
91 *
92 * @param endTime
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
96 * 'endTime'.
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.
101 */
102 public void closeHistory(long endTime) throws TimeRangeException {
103 File attributeTreeFile;
104 long attributeTreeFilePos;
105 long realEndTime = endTime;
106
107 if (realEndTime < backend.getEndTime()) {
108 /*
109 * This can happen (empty nodes pushing the border further, etc.)
110 * but shouldn't be too big of a deal.
111 */
112 realEndTime = backend.getEndTime();
113 }
114 transState.closeTransientState(realEndTime);
115 backend.finishedBuilding(realEndTime);
116
117 attributeTreeFile = backend.supplyAttributeTreeWriterFile();
118 attributeTreeFilePos = backend.supplyAttributeTreeWriterFilePosition();
119 if (attributeTreeFile != null) {
120 /*
121 * If null was returned, we simply won't save the attribute tree,
122 * too bad!
123 */
124 attributeTree.writeSelf(attributeTreeFile, attributeTreeFilePos);
125 }
126 }
127
128 /**
129 * @name External query methods
130 */
131
132 /**
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'.
136 *
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.
141 *
142 * @param t
143 * We will recreate the state information to what it was at time
144 * t.
145 * @throws TimeRangeException
146 */
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);
153 }
154
155 backend.doQuery(currentStateInfo, t);
156
157 if (transState.isActive()) {
158 transState.doQuery(currentStateInfo, t);
159 }
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);
165 }
166 }
167
168 /**
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.
172 *
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
177 */
178 public ITmfStateInterval queryState(int attributeQuark) {
179 return currentStateInfo.get(attributeQuark);
180 }
181
182 /**
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.
186 *
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.
191 *
192 * @param t
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
199 */
200 public ITmfStateInterval querySingleState(long t, int attributeQuark)
201 throws AttributeNotFoundException, TimeRangeException {
202 ITmfStateInterval ret;
203
204 if (transState.hasInfoAboutStateOf(t, attributeQuark)) {
205 ret = transState.getOngoingInterval(attributeQuark);
206 } else {
207 ret = backend.doSingularQuery(t, attributeQuark);
208 }
209 assert (ret != null);
210 return ret;
211 }
212
213 /**
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
216 * ascending time.
217 *
218 * @param attributeQuark
219 * Which attribute this query is interested in
220 * @param t1
221 * Start time of the range query
222 * @param t2
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
227 */
228 public List<ITmfStateInterval> queryHistoryRange(int attributeQuark, long t1,
229 long t2) throws TimeRangeException, AttributeNotFoundException {
230
231 List<ITmfStateInterval> intervals = new ArrayList<ITmfStateInterval>();
232 ITmfStateInterval currentInterval;
233 long ts;
234
235 /* Get the initial state at time T1 */
236 currentInterval = querySingleState(t1, attributeQuark);
237 intervals.add(currentInterval);
238
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();
246 }
247 return intervals;
248 }
249
250 /**
251 * @name Debugging methods
252 */
253
254 /**
255 * Print out the contents of the inner structures to the selected
256 * PrintWriter.
257 */
258 @Override
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$
267 } else {
268 writer.println(currentStateInfo.get(i).toString());
269 }
270 }
271 writer.println('\n');
272
273 /* Print the other inner containers */
274 super.debugPrint(writer);
275 backend.debugPrint(writer);
276 }
277 }
This page took 0.042753 seconds and 5 git commands to generate.