ss: History trees can define their own node types
[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, 2016 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.nio.channels.ClosedChannelException;
22 import java.util.Deque;
23 import java.util.LinkedList;
24 import java.util.List;
25
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.tracecompass.internal.statesystem.core.Activator;
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 import com.google.common.annotations.VisibleForTesting;
36
37 /**
38 * History Tree backend for storing a state history. This is the basic version
39 * that runs in the same thread as the class creating it.
40 *
41 * @author Alexandre Montplaisir
42 */
43 public class HistoryTreeBackend implements IStateHistoryBackend {
44
45 private final @NonNull String fSsid;
46
47 /**
48 * The history tree that sits underneath.
49 */
50 private final @NonNull IHistoryTree fSht;
51
52 /** Indicates if the history tree construction is done */
53 private volatile boolean fFinishedBuilding = false;
54
55 /**
56 * Indicates if the history tree construction is done
57 *
58 * @return if the history tree construction is done
59 */
60 protected boolean isFinishedBuilding() {
61 return fFinishedBuilding;
62 }
63
64 /**
65 * Sets if the history tree is finished building
66 *
67 * @param isFinishedBuilding
68 * is the history tree finished building
69 */
70 protected void setFinishedBuilding(boolean isFinishedBuilding) {
71 fFinishedBuilding = isFinishedBuilding;
72 }
73
74 /**
75 * Constructor for new history files. Use this when creating a new history
76 * from scratch.
77 *
78 * @param ssid
79 * The state system's ID
80 * @param newStateFile
81 * The filename/location where to store the state history (Should
82 * end in .ht)
83 * @param providerVersion
84 * Version of of the state provider. We will only try to reopen
85 * existing files if this version matches the one in the
86 * framework.
87 * @param startTime
88 * The earliest time stamp that will be stored in the history
89 * @param blockSize
90 * The size of the blocks in the history file. This should be a
91 * multiple of 4096.
92 * @param maxChildren
93 * The maximum number of children each core node can have
94 * @throws IOException
95 * Thrown if we can't create the file for some reason
96 */
97 public HistoryTreeBackend(@NonNull String ssid,
98 File newStateFile,
99 int providerVersion,
100 long startTime,
101 int blockSize,
102 int maxChildren) throws IOException {
103 fSsid = ssid;
104 final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren,
105 providerVersion, startTime);
106 fSht = initializeSHT(conf);
107 }
108
109 /**
110 * Constructor for new history files. Use this when creating a new history
111 * from scratch. This version supplies sane defaults for the configuration
112 * parameters.
113 *
114 * @param ssid
115 * The state system's id
116 * @param newStateFile
117 * The filename/location where to store the state history (Should
118 * end in .ht)
119 * @param providerVersion
120 * Version of of the state provider. We will only try to reopen
121 * existing files if this version matches the one in the
122 * framework.
123 * @param startTime
124 * The earliest time stamp that will be stored in the history
125 * @throws IOException
126 * Thrown if we can't create the file for some reason
127 * @since 1.0
128 */
129 public HistoryTreeBackend(@NonNull String ssid, File newStateFile, int providerVersion, long startTime)
130 throws IOException {
131 this(ssid, newStateFile, providerVersion, startTime, 64 * 1024, 50);
132 }
133
134 /**
135 * Existing history constructor. Use this to open an existing state-file.
136 *
137 * @param ssid
138 * The state system's id
139 * @param existingStateFile
140 * Filename/location of the history we want to load
141 * @param providerVersion
142 * Expected version of of the state provider plugin.
143 * @throws IOException
144 * If we can't read the file, if it doesn't exist, is not
145 * recognized, or if the version of the file does not match the
146 * expected providerVersion.
147 */
148 public HistoryTreeBackend(@NonNull String ssid, @NonNull File existingStateFile, int providerVersion)
149 throws IOException {
150 fSsid = ssid;
151 fSht = initializeSHT(existingStateFile, providerVersion);
152 fFinishedBuilding = true;
153 }
154
155 /**
156 * New-tree initializer for the History Tree wrapped by this backend. Can be
157 * overriden to use different implementations.
158 *
159 * @param conf
160 * The HTConfig configuration object
161 * @return The new history tree
162 * @throws IOException
163 * If there was a problem during creation
164 */
165 @VisibleForTesting
166 protected @NonNull IHistoryTree initializeSHT(@NonNull HTConfig conf) throws IOException {
167 return HistoryTreeFactory.createHistoryTree(conf);
168 }
169
170 /**
171 * Existing-tree initializer for the History Tree wrapped by this backend.
172 * Can be overriden to use different implementations.
173 *
174 * @param existingStateFile
175 * The file to open
176 * @param providerVersion
177 * The expected state provider version
178 * @return The history tree opened from the given file
179 * @throws IOException
180 * If there was a problem during creation
181 */
182 @VisibleForTesting
183 protected @NonNull IHistoryTree initializeSHT(@NonNull File existingStateFile, int providerVersion) throws IOException {
184 return HistoryTreeFactory.createFromFile(existingStateFile.toPath(), providerVersion);
185 }
186
187 /**
188 * Get the History Tree built by this backend.
189 *
190 * Note: Do not override this method. If you want to extend the class to use
191 * a different History Tree implementation, override both variants of
192 * {@link #initializeSHT} instead.
193 *
194 * @return The history tree
195 */
196 protected final @NonNull IHistoryTree getSHT() {
197 return fSht;
198 }
199
200 @Override
201 public String getSSID() {
202 return fSsid;
203 }
204
205 @Override
206 public long getStartTime() {
207 return getSHT().getTreeStart();
208 }
209
210 @Override
211 public long getEndTime() {
212 return getSHT().getTreeEnd();
213 }
214
215 @Override
216 public void insertPastState(long stateStartTime, long stateEndTime,
217 int quark, ITmfStateValue value) throws TimeRangeException {
218 HTInterval interval = new HTInterval(stateStartTime, stateEndTime,
219 quark, (TmfStateValue) value);
220
221 /* Start insertions at the "latest leaf" */
222 getSHT().insertInterval(interval);
223 }
224
225 @Override
226 public void finishedBuilding(long endTime) {
227 getSHT().closeTree(endTime);
228 fFinishedBuilding = true;
229 }
230
231 @Override
232 public FileInputStream supplyAttributeTreeReader() {
233 return getSHT().supplyATReader();
234 }
235
236 @Override
237 public File supplyAttributeTreeWriterFile() {
238 return getSHT().supplyATWriterFile();
239 }
240
241 @Override
242 public long supplyAttributeTreeWriterFilePosition() {
243 return getSHT().supplyATWriterFilePos();
244 }
245
246 @Override
247 public void removeFiles() {
248 getSHT().deleteFile();
249 }
250
251 @Override
252 public void dispose() {
253 if (fFinishedBuilding) {
254 getSHT().closeFile();
255 } else {
256 /*
257 * The build is being interrupted, delete the file we partially
258 * built since it won't be complete, so shouldn't be re-used in the
259 * future (.deleteFile() will close the file first)
260 */
261 getSHT().deleteFile();
262 }
263 }
264
265 @Override
266 public void doQuery(List<ITmfStateInterval> stateInfo, long t)
267 throws TimeRangeException, StateSystemDisposedException {
268 checkValidTime(t);
269
270 /* Queue is a stack of nodes containing nodes intersecting t */
271 Deque<HTNode> queue = new LinkedList<>();
272
273 /* We start by reading the information in the root node */
274 queue.add(getSHT().getRootNode());
275
276 /* Then we follow the down in the relevant children */
277 try {
278 while (!queue.isEmpty()) {
279 HTNode currentNode = queue.pop();
280 if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
281 /*Here we add the relevant children nodes for BFS*/
282 queue.addAll(getSHT().selectNextChildren((ParentNode) currentNode, t));
283 }
284 currentNode.writeInfoFromNode(stateInfo, t);
285 }
286 } catch (ClosedChannelException e) {
287 throw new StateSystemDisposedException(e);
288 }
289
290 /*
291 * The stateInfo should now be filled with everything needed, we pass
292 * the control back to the State System.
293 */
294 }
295
296 @Override
297 public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
298 throws TimeRangeException, StateSystemDisposedException {
299 try {
300 return getRelevantInterval(t, attributeQuark);
301 } catch (ClosedChannelException e) {
302 throw new StateSystemDisposedException(e);
303 }
304 }
305
306 private void checkValidTime(long t) {
307 long startTime = getStartTime();
308 long endTime = getEndTime();
309 if (t < startTime || t > endTime) {
310 throw new TimeRangeException(String.format("%s Time:%d, Start:%d, End:%d", //$NON-NLS-1$
311 fSsid, t, startTime, endTime));
312 }
313 }
314
315 /**
316 * Inner method to find the interval in the tree containing the requested
317 * key/timestamp pair, wherever in which node it is.
318 */
319 private HTInterval getRelevantInterval(long t, int key)
320 throws TimeRangeException, ClosedChannelException {
321 checkValidTime(t);
322
323 Deque<HTNode> queue = new LinkedList<>();
324 queue.add(getSHT().getRootNode());
325 HTInterval interval = null;
326 while (interval == null && !queue.isEmpty()) {
327 HTNode currentNode = queue.pop();
328 if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
329 queue.addAll(getSHT().selectNextChildren((ParentNode) currentNode, t));
330 }
331 interval = currentNode.getRelevantInterval(key, t);
332 }
333 return interval;
334 }
335
336 /**
337 * Return the size of the tree history file
338 *
339 * @return The current size of the history file in bytes
340 */
341 public long getFileSize() {
342 return getSHT().getFileSize();
343 }
344
345 /**
346 * Return the average node usage as a percentage (between 0 and 100)
347 *
348 * @return Average node usage %
349 */
350 public int getAverageNodeUsage() {
351 HTNode node;
352 long total = 0;
353 long ret;
354
355 try {
356 for (int seq = 0; seq < getSHT().getNodeCount(); seq++) {
357 node = getSHT().readNode(seq);
358 total += node.getNodeUsagePercent();
359 }
360 } catch (ClosedChannelException e) {
361 Activator.getDefault().logError(e.getMessage(), e);
362 }
363
364 ret = total / getSHT().getNodeCount();
365 /* The return value should be a percentage */
366 if (ret < 0 || ret > 100) {
367 throw new IllegalStateException("Average node usage is not a percentage: " + ret); //$NON-NLS-1$
368 }
369 return (int) ret;
370 }
371
372 }
This page took 0.039198 seconds and 5 git commands to generate.