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