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
CommitLineData
a52fde77 1/*******************************************************************************
e8aa3325 2 * Copyright (c) 2012, 2016 Ericsson
a52fde77
AM
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5df842b3 5 *
a52fde77
AM
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
5df842b3 10 *
e13bd4cd
PT
11 * Contributors:
12 * Alexandre Montplaisir - Initial API and implementation
13 * Patrick Tasse - Add message to exceptions
a52fde77
AM
14 *******************************************************************************/
15
0306a843 16package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
a52fde77
AM
17
18import java.io.File;
19import java.io.FileInputStream;
20import java.io.IOException;
3b7f5abe 21import java.nio.channels.ClosedChannelException;
588f11a1
LPD
22import java.util.Deque;
23import java.util.LinkedList;
a52fde77
AM
24import java.util.List;
25
b2f62cb5 26import org.eclipse.jdt.annotation.NonNull;
0e9b2f07 27import org.eclipse.tracecompass.internal.statesystem.core.Activator;
e894a508
AM
28import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
29import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
30import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
31import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
32import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
33import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
a52fde77 34
068641fa
GB
35import com.google.common.annotations.VisibleForTesting;
36
a52fde77
AM
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.
5df842b3 40 *
360f899e 41 * @author Alexandre Montplaisir
a52fde77
AM
42 */
43public class HistoryTreeBackend implements IStateHistoryBackend {
44
0e9b2f07 45 private final @NonNull String fSsid;
b2f62cb5 46
bcec0116
AM
47 /**
48 * The history tree that sits underneath.
bcec0116 49 */
3a081e85 50 private final @NonNull IHistoryTree fSht;
6f4e8ec0 51
1a4205d9 52 /** Indicates if the history tree construction is done */
d740e018
MK
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) {
0e9b2f07 71 fFinishedBuilding = isFinishedBuilding;
d740e018 72 }
1a4205d9 73
a52fde77 74 /**
7453b40e 75 * Constructor for new history files. Use this when creating a new history
a52fde77 76 * from scratch.
5df842b3 77 *
b2f62cb5
AM
78 * @param ssid
79 * The state system's ID
a52fde77
AM
80 * @param newStateFile
81 * The filename/location where to store the state history (Should
82 * end in .ht)
a96cc6be
AM
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.
a52fde77
AM
87 * @param startTime
88 * The earliest time stamp that will be stored in the history
f6d24a71
AM
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
a52fde77
AM
94 * @throws IOException
95 * Thrown if we can't create the file for some reason
96 */
f6d24a71
AM
97 public HistoryTreeBackend(@NonNull String ssid,
98 File newStateFile,
99 int providerVersion,
100 long startTime,
101 int blockSize,
102 int maxChildren) throws IOException {
0e9b2f07 103 fSsid = ssid;
a96cc6be
AM
104 final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren,
105 providerVersion, startTime);
068641fa 106 fSht = initializeSHT(conf);
a52fde77
AM
107 }
108
109 /**
7453b40e 110 * Constructor for new history files. Use this when creating a new history
a52fde77
AM
111 * from scratch. This version supplies sane defaults for the configuration
112 * parameters.
5df842b3 113 *
b2f62cb5
AM
114 * @param ssid
115 * The state system's id
a52fde77
AM
116 * @param newStateFile
117 * The filename/location where to store the state history (Should
118 * end in .ht)
a96cc6be
AM
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.
a52fde77
AM
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
dbc7991d 127 * @since 1.0
a52fde77 128 */
b2f62cb5 129 public HistoryTreeBackend(@NonNull String ssid, File newStateFile, int providerVersion, long startTime)
a52fde77 130 throws IOException {
f6d24a71 131 this(ssid, newStateFile, providerVersion, startTime, 64 * 1024, 50);
a52fde77
AM
132 }
133
134 /**
135 * Existing history constructor. Use this to open an existing state-file.
5df842b3 136 *
b2f62cb5
AM
137 * @param ssid
138 * The state system's id
0d9a6d76 139 * @param existingStateFile
b255ae4b 140 * Filename/location of the history we want to load
a96cc6be
AM
141 * @param providerVersion
142 * Expected version of of the state provider plugin.
b255ae4b 143 * @throws IOException
a96cc6be
AM
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.
a52fde77 147 */
068641fa 148 public HistoryTreeBackend(@NonNull String ssid, @NonNull File existingStateFile, int providerVersion)
a96cc6be 149 throws IOException {
0e9b2f07 150 fSsid = ssid;
068641fa 151 fSht = initializeSHT(existingStateFile, providerVersion);
d740e018 152 fFinishedBuilding = true;
a52fde77
AM
153 }
154
068641fa
GB
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
3a081e85 166 protected @NonNull IHistoryTree initializeSHT(@NonNull HTConfig conf) throws IOException {
9a4c098d 167 return HistoryTreeFactory.createHistoryTree(conf);
068641fa
GB
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
3a081e85 183 protected @NonNull IHistoryTree initializeSHT(@NonNull File existingStateFile, int providerVersion) throws IOException {
9a4c098d 184 return HistoryTreeFactory.createFromFile(existingStateFile.toPath(), providerVersion);
068641fa
GB
185 }
186
e62a23a9
AM
187 /**
188 * Get the History Tree built by this backend.
189 *
068641fa
GB
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 *
e62a23a9
AM
194 * @return The history tree
195 */
3a081e85 196 protected final @NonNull IHistoryTree getSHT() {
0e9b2f07 197 return fSht;
e62a23a9
AM
198 }
199
b2f62cb5
AM
200 @Override
201 public String getSSID() {
0e9b2f07 202 return fSsid;
b2f62cb5
AM
203 }
204
a52fde77
AM
205 @Override
206 public long getStartTime() {
068641fa 207 return getSHT().getTreeStart();
a52fde77
AM
208 }
209
210 @Override
211 public long getEndTime() {
068641fa 212 return getSHT().getTreeEnd();
a52fde77
AM
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" */
068641fa 222 getSHT().insertInterval(interval);
a52fde77
AM
223 }
224
225 @Override
b33c7369 226 public void finishedBuilding(long endTime) {
068641fa 227 getSHT().closeTree(endTime);
d740e018 228 fFinishedBuilding = true;
a52fde77
AM
229 }
230
231 @Override
232 public FileInputStream supplyAttributeTreeReader() {
068641fa 233 return getSHT().supplyATReader();
a52fde77
AM
234 }
235
236 @Override
237 public File supplyAttributeTreeWriterFile() {
068641fa 238 return getSHT().supplyATWriterFile();
a52fde77
AM
239 }
240
241 @Override
242 public long supplyAttributeTreeWriterFilePosition() {
068641fa 243 return getSHT().supplyATWriterFilePos();
a52fde77
AM
244 }
245
36bf82a2
AM
246 @Override
247 public void removeFiles() {
068641fa 248 getSHT().deleteFile();
36bf82a2
AM
249 }
250
1a4205d9
AM
251 @Override
252 public void dispose() {
d740e018 253 if (fFinishedBuilding) {
068641fa 254 getSHT().closeFile();
1a4205d9
AM
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 */
068641fa 261 getSHT().deleteFile();
1a4205d9
AM
262 }
263 }
264
a52fde77
AM
265 @Override
266 public void doQuery(List<ITmfStateInterval> stateInfo, long t)
3b7f5abe 267 throws TimeRangeException, StateSystemDisposedException {
e13bd4cd 268 checkValidTime(t);
a52fde77 269
588f11a1
LPD
270 /* Queue is a stack of nodes containing nodes intersecting t */
271 Deque<HTNode> queue = new LinkedList<>();
272
a52fde77 273 /* We start by reading the information in the root node */
588f11a1 274 queue.add(getSHT().getRootNode());
a52fde77 275
588f11a1 276 /* Then we follow the down in the relevant children */
3b7f5abe 277 try {
588f11a1
LPD
278 while (!queue.isEmpty()) {
279 HTNode currentNode = queue.pop();
280 if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
f4baf640
GB
281 /*Here we add the relevant children nodes for BFS*/
282 queue.addAll(getSHT().selectNextChildren((ParentNode) currentNode, t));
588f11a1 283 }
3b7f5abe
AM
284 currentNode.writeInfoFromNode(stateInfo, t);
285 }
286 } catch (ClosedChannelException e) {
cb42195c 287 throw new StateSystemDisposedException(e);
a52fde77
AM
288 }
289
290 /*
291 * The stateInfo should now be filled with everything needed, we pass
292 * the control back to the State System.
293 */
a52fde77
AM
294 }
295
296 @Override
297 public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
3b7f5abe 298 throws TimeRangeException, StateSystemDisposedException {
588f11a1
LPD
299 try {
300 return getRelevantInterval(t, attributeQuark);
301 } catch (ClosedChannelException e) {
302 throw new StateSystemDisposedException(e);
303 }
a52fde77
AM
304 }
305
e13bd4cd 306 private void checkValidTime(long t) {
e8aa3325
PT
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));
e13bd4cd 312 }
a52fde77
AM
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.
a52fde77
AM
318 */
319 private HTInterval getRelevantInterval(long t, int key)
588f11a1 320 throws TimeRangeException, ClosedChannelException {
e13bd4cd 321 checkValidTime(t);
a52fde77 322
588f11a1
LPD
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) {
f4baf640 329 queue.addAll(getSHT().selectNextChildren((ParentNode) currentNode, t));
3b7f5abe 330 }
588f11a1 331 interval = currentNode.getRelevantInterval(key, t);
a52fde77 332 }
a52fde77
AM
333 return interval;
334 }
335
336 /**
337 * Return the size of the tree history file
5df842b3 338 *
a52fde77
AM
339 * @return The current size of the history file in bytes
340 */
341 public long getFileSize() {
068641fa 342 return getSHT().getFileSize();
a52fde77
AM
343 }
344
a52fde77
AM
345 /**
346 * Return the average node usage as a percentage (between 0 and 100)
5df842b3 347 *
a52fde77
AM
348 * @return Average node usage %
349 */
350 public int getAverageNodeUsage() {
351 HTNode node;
352 long total = 0;
353 long ret;
354
3b7f5abe 355 try {
068641fa
GB
356 for (int seq = 0; seq < getSHT().getNodeCount(); seq++) {
357 node = getSHT().readNode(seq);
8d47cc34 358 total += node.getNodeUsagePercent();
3b7f5abe
AM
359 }
360 } catch (ClosedChannelException e) {
0e9b2f07 361 Activator.getDefault().logError(e.getMessage(), e);
a52fde77
AM
362 }
363
068641fa 364 ret = total / getSHT().getNodeCount();
822798a3 365 /* The return value should be a percentage */
09e814aa 366 if (ret < 0 || ret > 100) {
822798a3
GB
367 throw new IllegalStateException("Average node usage is not a percentage: " + ret); //$NON-NLS-1$
368 }
a52fde77
AM
369 return (int) ret;
370 }
371
a52fde77 372}
This page took 0.105238 seconds and 5 git commands to generate.