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