1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
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
12 * Alexandre Montplaisir - Initial API and implementation
13 * Patrick Tasse - Add message to exceptions
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.statesystem
.core
.backend
.historytree
;
19 import java
.io
.FileInputStream
;
20 import java
.io
.IOException
;
21 import java
.io
.PrintWriter
;
22 import java
.nio
.channels
.ClosedChannelException
;
23 import java
.util
.List
;
25 import org
.eclipse
.jdt
.annotation
.NonNull
;
26 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.CoreNode
;
27 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTConfig
;
28 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTInterval
;
29 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTNode
;
30 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HistoryTree
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
34 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
35 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
36 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
39 * History Tree backend for storing a state history. This is the basic version
40 * that runs in the same thread as the class creating it.
42 * @author Alexandre Montplaisir
44 public class HistoryTreeBackend
implements IStateHistoryBackend
{
46 private final @NonNull String ssid
;
49 * The history tree that sits underneath.
51 private final HistoryTree sht
;
53 /** Indicates if the history tree construction is done */
54 private volatile boolean fFinishedBuilding
= false;
57 * Indicates if the history tree construction is done
59 * @return if the history tree construction is done
62 protected boolean isFinishedBuilding() {
63 return fFinishedBuilding
;
67 * Sets if the history tree is finished building
69 * @param isFinishedBuilding
70 * is the history tree finished building
73 protected void setFinishedBuilding(boolean isFinishedBuilding
) {
74 this.fFinishedBuilding
= isFinishedBuilding
;
78 * Constructor for new history files. Use this when creating a new history
82 * The state system's ID
84 * The filename/location where to store the state history (Should
87 * The size of the blocks in the history file. This should be a
90 * The maximum number of children each core node can have
91 * @param providerVersion
92 * Version of of the state provider. We will only try to reopen
93 * existing files if this version matches the one in the
96 * The earliest time stamp that will be stored in the history
98 * Thrown if we can't create the file for some reason
101 public HistoryTreeBackend(@NonNull String ssid
, File newStateFile
, int blockSize
,
102 int maxChildren
, int providerVersion
, long startTime
) throws IOException
{
104 final HTConfig conf
= new HTConfig(newStateFile
, blockSize
, maxChildren
,
105 providerVersion
, startTime
);
106 sht
= new HistoryTree(conf
);
110 * Constructor for new history files. Use this when creating a new history
111 * from scratch. This version supplies sane defaults for the configuration
115 * The state system's id
116 * @param newStateFile
117 * The filename/location where to store the state history (Should
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
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
129 public HistoryTreeBackend(@NonNull String ssid
, File newStateFile
, int providerVersion
, long startTime
)
131 this(ssid
, newStateFile
, 64 * 1024, 50, providerVersion
, startTime
);
135 * Existing history constructor. Use this to open an existing state-file.
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.
149 public HistoryTreeBackend(@NonNull String ssid
, File existingStateFile
, int providerVersion
)
152 sht
= new HistoryTree(existingStateFile
, providerVersion
);
153 fFinishedBuilding
= true;
157 * Get the History Tree built by this backend.
159 * @return The history tree
161 protected HistoryTree
getSHT() {
169 public String
getSSID() {
174 public long getStartTime() {
175 return sht
.getTreeStart();
179 public long getEndTime() {
180 return sht
.getTreeEnd();
184 public void insertPastState(long stateStartTime
, long stateEndTime
,
185 int quark
, ITmfStateValue value
) throws TimeRangeException
{
186 HTInterval interval
= new HTInterval(stateStartTime
, stateEndTime
,
187 quark
, (TmfStateValue
) value
);
189 /* Start insertions at the "latest leaf" */
190 sht
.insertInterval(interval
);
194 public void finishedBuilding(long endTime
) {
195 sht
.closeTree(endTime
);
196 fFinishedBuilding
= true;
200 public FileInputStream
supplyAttributeTreeReader() {
201 return sht
.supplyATReader();
205 public File
supplyAttributeTreeWriterFile() {
206 return sht
.supplyATWriterFile();
210 public long supplyAttributeTreeWriterFilePosition() {
211 return sht
.supplyATWriterFilePos();
215 public void removeFiles() {
220 public void dispose() {
221 if (fFinishedBuilding
) {
225 * The build is being interrupted, delete the file we partially
226 * built since it won't be complete, so shouldn't be re-used in the
227 * future (.deleteFile() will close the file first)
234 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
)
235 throws TimeRangeException
, StateSystemDisposedException
{
238 /* We start by reading the information in the root node */
239 HTNode currentNode
= sht
.getRootNode();
240 currentNode
.writeInfoFromNode(stateInfo
, t
);
242 /* Then we follow the branch down in the relevant children */
244 while (currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
245 currentNode
= sht
.selectNextChild((CoreNode
) currentNode
, t
);
246 currentNode
.writeInfoFromNode(stateInfo
, t
);
248 } catch (ClosedChannelException e
) {
249 throw new StateSystemDisposedException(e
);
253 * The stateInfo should now be filled with everything needed, we pass
254 * the control back to the State System.
260 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
261 throws TimeRangeException
, StateSystemDisposedException
{
262 return getRelevantInterval(t
, attributeQuark
);
265 private void checkValidTime(long t
) {
266 long treeStart
= sht
.getTreeStart();
267 long treeEnd
= sht
.getTreeEnd();
268 if (t
< treeStart
|| t
> treeEnd
) {
269 throw new TimeRangeException(ssid
+ " Time:" + t
+ ", Start:" + treeStart
+ ", End:" + treeEnd
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
274 * Inner method to find the interval in the tree containing the requested
275 * key/timestamp pair, wherever in which node it is.
279 * @return The node containing the information we want
281 private HTInterval
getRelevantInterval(long t
, int key
)
282 throws TimeRangeException
, StateSystemDisposedException
{
285 HTNode currentNode
= sht
.getRootNode();
286 HTInterval interval
= currentNode
.getRelevantInterval(key
, t
);
289 while (interval
== null && currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
290 currentNode
= sht
.selectNextChild((CoreNode
) currentNode
, t
);
291 interval
= currentNode
.getRelevantInterval(key
, t
);
293 } catch (ClosedChannelException e
) {
294 throw new StateSystemDisposedException(e
);
300 * Return the size of the tree history file
302 * @return The current size of the history file in bytes
304 public long getFileSize() {
305 return sht
.getFileSize();
309 * Return the average node usage as a percentage (between 0 and 100)
311 * @return Average node usage %
313 public int getAverageNodeUsage() {
319 for (int seq
= 0; seq
< sht
.getNodeCount(); seq
++) {
320 node
= sht
.readNode(seq
);
321 total
+= node
.getNodeUsagePercent();
323 } catch (ClosedChannelException e
) {
327 ret
= total
/ sht
.getNodeCount();
328 assert (ret
>= 0 && ret
<= 100);
333 public void debugPrint(PrintWriter writer
) {
334 /* By default don't print out all the intervals */
335 this.debugPrint(writer
, false);
339 * The basic debugPrint method will print the tree structure, but not their
342 * This method here print the contents (the intervals) as well.
345 * The PrintWriter to which the debug info will be written
346 * @param printIntervals
347 * Should we also print every contained interval individually?
349 public void debugPrint(PrintWriter writer
, boolean printIntervals
) {
350 /* Only used for debugging, shouldn't be externalized */
351 writer
.println("------------------------------"); //$NON-NLS-1$
352 writer
.println("State History Tree:\n"); //$NON-NLS-1$
353 writer
.println(sht
.toString());
354 writer
.println("Average node utilization: " //$NON-NLS-1$
355 + this.getAverageNodeUsage());
356 writer
.println(""); //$NON-NLS-1$
358 sht
.debugPrintFullTree(writer
, printIntervals
);