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