statesystem: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / HistoryTreeBackend.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 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 * Contributors:
12 * Alexandre Montplaisir - Initial API and implementation
13 * Patrick Tasse - Add message to exceptions
14 *******************************************************************************/
15
16 package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
17
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.IOException;
21 import java.io.PrintWriter;
22 import java.nio.channels.ClosedChannelException;
23 import java.util.List;
24
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.CoreNode;
27 import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTConfig;
28 import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTInterval;
29 import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTNode;
30 import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HistoryTree;
31 import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
32 import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
33 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
34 import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
35 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
36 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
37
38 /**
39 * History Tree backend for storing a state history. This is the basic version
40 * that runs in the same thread as the class creating it.
41 *
42 * @author Alexandre Montplaisir
43 */
44 public class HistoryTreeBackend implements IStateHistoryBackend {
45
46 private final @NonNull String ssid;
47
48 /**
49 * The history tree that sits underneath.
50 */
51 private final HistoryTree sht;
52
53 /** Indicates if the history tree construction is done */
54 private volatile boolean fFinishedBuilding = false;
55
56 /**
57 * Indicates if the history tree construction is done
58 *
59 * @return if the history tree construction is done
60 */
61 protected boolean isFinishedBuilding() {
62 return fFinishedBuilding;
63 }
64
65 /**
66 * Sets if the history tree is finished building
67 *
68 * @param isFinishedBuilding
69 * is the history tree finished building
70 */
71 protected void setFinishedBuilding(boolean isFinishedBuilding) {
72 this.fFinishedBuilding = isFinishedBuilding;
73 }
74
75 /**
76 * Constructor for new history files. Use this when creating a new history
77 * from scratch.
78 *
79 * @param ssid
80 * The state system's ID
81 * @param newStateFile
82 * The filename/location where to store the state history (Should
83 * end in .ht)
84 * @param providerVersion
85 * Version of of the state provider. We will only try to reopen
86 * existing files if this version matches the one in the
87 * framework.
88 * @param startTime
89 * The earliest time stamp that will be stored in the history
90 * @param blockSize
91 * The size of the blocks in the history file. This should be a
92 * multiple of 4096.
93 * @param maxChildren
94 * The maximum number of children each core node can have
95 * @throws IOException
96 * Thrown if we can't create the file for some reason
97 */
98 public HistoryTreeBackend(@NonNull String ssid,
99 File newStateFile,
100 int providerVersion,
101 long startTime,
102 int blockSize,
103 int maxChildren) throws IOException {
104 this.ssid = ssid;
105 final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren,
106 providerVersion, startTime);
107 sht = new HistoryTree(conf);
108 }
109
110 /**
111 * Constructor for new history files. Use this when creating a new history
112 * from scratch. This version supplies sane defaults for the configuration
113 * parameters.
114 *
115 * @param ssid
116 * The state system's id
117 * @param newStateFile
118 * The filename/location where to store the state history (Should
119 * end in .ht)
120 * @param providerVersion
121 * Version of of the state provider. We will only try to reopen
122 * existing files if this version matches the one in the
123 * framework.
124 * @param startTime
125 * The earliest time stamp that will be stored in the history
126 * @throws IOException
127 * Thrown if we can't create the file for some reason
128 * @since 1.0
129 */
130 public HistoryTreeBackend(@NonNull String ssid, File newStateFile, int providerVersion, long startTime)
131 throws IOException {
132 this(ssid, newStateFile, providerVersion, startTime, 64 * 1024, 50);
133 }
134
135 /**
136 * Existing history constructor. Use this to open an existing state-file.
137 *
138 * @param ssid
139 * The state system's id
140 * @param existingStateFile
141 * Filename/location of the history we want to load
142 * @param providerVersion
143 * Expected version of of the state provider plugin.
144 * @throws IOException
145 * If we can't read the file, if it doesn't exist, is not
146 * recognized, or if the version of the file does not match the
147 * expected providerVersion.
148 */
149 public HistoryTreeBackend(@NonNull String ssid, File existingStateFile, int providerVersion)
150 throws IOException {
151 this.ssid = ssid;
152 sht = new HistoryTree(existingStateFile, providerVersion);
153 fFinishedBuilding = true;
154 }
155
156 /**
157 * Get the History Tree built by this backend.
158 *
159 * @return The history tree
160 */
161 protected HistoryTree getSHT() {
162 return sht;
163 }
164
165 @Override
166 public String getSSID() {
167 return ssid;
168 }
169
170 @Override
171 public long getStartTime() {
172 return sht.getTreeStart();
173 }
174
175 @Override
176 public long getEndTime() {
177 return sht.getTreeEnd();
178 }
179
180 @Override
181 public void insertPastState(long stateStartTime, long stateEndTime,
182 int quark, ITmfStateValue value) throws TimeRangeException {
183 HTInterval interval = new HTInterval(stateStartTime, stateEndTime,
184 quark, (TmfStateValue) value);
185
186 /* Start insertions at the "latest leaf" */
187 sht.insertInterval(interval);
188 }
189
190 @Override
191 public void finishedBuilding(long endTime) {
192 sht.closeTree(endTime);
193 fFinishedBuilding = true;
194 }
195
196 @Override
197 public FileInputStream supplyAttributeTreeReader() {
198 return sht.supplyATReader();
199 }
200
201 @Override
202 public File supplyAttributeTreeWriterFile() {
203 return sht.supplyATWriterFile();
204 }
205
206 @Override
207 public long supplyAttributeTreeWriterFilePosition() {
208 return sht.supplyATWriterFilePos();
209 }
210
211 @Override
212 public void removeFiles() {
213 sht.deleteFile();
214 }
215
216 @Override
217 public void dispose() {
218 if (fFinishedBuilding) {
219 sht.closeFile();
220 } else {
221 /*
222 * The build is being interrupted, delete the file we partially
223 * built since it won't be complete, so shouldn't be re-used in the
224 * future (.deleteFile() will close the file first)
225 */
226 sht.deleteFile();
227 }
228 }
229
230 @Override
231 public void doQuery(List<ITmfStateInterval> stateInfo, long t)
232 throws TimeRangeException, StateSystemDisposedException {
233 checkValidTime(t);
234
235 /* We start by reading the information in the root node */
236 HTNode currentNode = sht.getRootNode();
237 currentNode.writeInfoFromNode(stateInfo, t);
238
239 /* Then we follow the branch down in the relevant children */
240 try {
241 while (currentNode.getNodeType() == HTNode.NodeType.CORE) {
242 currentNode = sht.selectNextChild((CoreNode) currentNode, t);
243 currentNode.writeInfoFromNode(stateInfo, t);
244 }
245 } catch (ClosedChannelException e) {
246 throw new StateSystemDisposedException(e);
247 }
248
249 /*
250 * The stateInfo should now be filled with everything needed, we pass
251 * the control back to the State System.
252 */
253 return;
254 }
255
256 @Override
257 public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
258 throws TimeRangeException, StateSystemDisposedException {
259 return getRelevantInterval(t, attributeQuark);
260 }
261
262 private void checkValidTime(long t) {
263 long treeStart = sht.getTreeStart();
264 long treeEnd = sht.getTreeEnd();
265 if (t < treeStart || t > treeEnd) {
266 throw new TimeRangeException(ssid + " Time:" + t + ", Start:" + treeStart + ", End:" + treeEnd); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
267 }
268 }
269
270 /**
271 * Inner method to find the interval in the tree containing the requested
272 * key/timestamp pair, wherever in which node it is.
273 *
274 * @param t
275 * @param key
276 * @return The node containing the information we want
277 */
278 private HTInterval getRelevantInterval(long t, int key)
279 throws TimeRangeException, StateSystemDisposedException {
280 checkValidTime(t);
281
282 HTNode currentNode = sht.getRootNode();
283 HTInterval interval = currentNode.getRelevantInterval(key, t);
284
285 try {
286 while (interval == null && currentNode.getNodeType() == HTNode.NodeType.CORE) {
287 currentNode = sht.selectNextChild((CoreNode) currentNode, t);
288 interval = currentNode.getRelevantInterval(key, t);
289 }
290 } catch (ClosedChannelException e) {
291 throw new StateSystemDisposedException(e);
292 }
293 return interval;
294 }
295
296 /**
297 * Return the size of the tree history file
298 *
299 * @return The current size of the history file in bytes
300 */
301 public long getFileSize() {
302 return sht.getFileSize();
303 }
304
305 /**
306 * Return the average node usage as a percentage (between 0 and 100)
307 *
308 * @return Average node usage %
309 */
310 public int getAverageNodeUsage() {
311 HTNode node;
312 long total = 0;
313 long ret;
314
315 try {
316 for (int seq = 0; seq < sht.getNodeCount(); seq++) {
317 node = sht.readNode(seq);
318 total += node.getNodeUsagePercent();
319 }
320 } catch (ClosedChannelException e) {
321 e.printStackTrace();
322 }
323
324 ret = total / sht.getNodeCount();
325 assert (ret >= 0 && ret <= 100);
326 return (int) ret;
327 }
328
329 @Override
330 public void debugPrint(PrintWriter writer) {
331 /* By default don't print out all the intervals */
332 this.debugPrint(writer, false);
333 }
334
335 /**
336 * The basic debugPrint method will print the tree structure, but not their
337 * contents.
338 *
339 * This method here print the contents (the intervals) as well.
340 *
341 * @param writer
342 * The PrintWriter to which the debug info will be written
343 * @param printIntervals
344 * Should we also print every contained interval individually?
345 */
346 public void debugPrint(PrintWriter writer, boolean printIntervals) {
347 /* Only used for debugging, shouldn't be externalized */
348 writer.println("------------------------------"); //$NON-NLS-1$
349 writer.println("State History Tree:\n"); //$NON-NLS-1$
350 writer.println(sht.toString());
351 writer.println("Average node utilization: " //$NON-NLS-1$
352 + this.getAverageNodeUsage());
353 writer.println(""); //$NON-NLS-1$
354
355 sht.debugPrintFullTree(writer, printIntervals);
356 }
357 }
This page took 0.040362 seconds and 6 git commands to generate.