1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 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
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.statesystem
.core
.backend
.historytree
;
16 import java
.io
.FileInputStream
;
17 import java
.io
.IOException
;
18 import java
.io
.PrintWriter
;
19 import java
.nio
.channels
.ClosedChannelException
;
20 import java
.util
.List
;
22 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.CoreNode
;
23 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTConfig
;
24 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTInterval
;
25 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTNode
;
26 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HistoryTree
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
35 * History Tree backend for storing a state history. This is the basic version
36 * that runs in the same thread as the class creating it.
38 * @author Alexandre Montplaisir
41 public class HistoryTreeBackend
implements IStateHistoryBackend
{
44 * The history tree that sits underneath.
46 private final HistoryTree sht
;
48 /** Indicates if the history tree construction is done */
49 protected volatile boolean isFinishedBuilding
= false;
52 * Constructor for new history files. Use this when creating a new history
56 * The filename/location where to store the state history (Should
59 * The size of the blocks in the history file. This should be a
62 * The maximum number of children each core node can have
63 * @param providerVersion
64 * Version of of the state provider. We will only try to reopen
65 * existing files if this version matches the one in the
68 * The earliest time stamp that will be stored in the history
70 * Thrown if we can't create the file for some reason
72 public HistoryTreeBackend(File newStateFile
, int blockSize
,
73 int maxChildren
, int providerVersion
, long startTime
) throws IOException
{
74 final HTConfig conf
= new HTConfig(newStateFile
, blockSize
, maxChildren
,
75 providerVersion
, startTime
);
76 sht
= new HistoryTree(conf
);
80 * Constructor for new history files. Use this when creating a new history
81 * from scratch. This version supplies sane defaults for the configuration
85 * The filename/location where to store the state history (Should
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
92 * The earliest time stamp that will be stored in the history
94 * Thrown if we can't create the file for some reason
96 public HistoryTreeBackend(File newStateFile
, int providerVersion
, long startTime
)
98 this(newStateFile
, 64 * 1024, 50, providerVersion
, startTime
);
102 * Existing history constructor. Use this to open an existing state-file.
104 * @param existingStateFile
105 * Filename/location of the history we want to load
106 * @param providerVersion
107 * Expected version of of the state provider plugin.
108 * @throws IOException
109 * If we can't read the file, if it doesn't exist, is not
110 * recognized, or if the version of the file does not match the
111 * expected providerVersion.
113 public HistoryTreeBackend(File existingStateFile
, int providerVersion
)
115 sht
= new HistoryTree(existingStateFile
, providerVersion
);
116 isFinishedBuilding
= true;
120 * Get the History Tree built by this backend.
122 * @return The history tree
124 protected HistoryTree
getSHT() {
129 public long getStartTime() {
130 return sht
.getTreeStart();
134 public long getEndTime() {
135 return sht
.getTreeEnd();
139 public void insertPastState(long stateStartTime
, long stateEndTime
,
140 int quark
, ITmfStateValue value
) throws TimeRangeException
{
141 HTInterval interval
= new HTInterval(stateStartTime
, stateEndTime
,
142 quark
, (TmfStateValue
) value
);
144 /* Start insertions at the "latest leaf" */
145 sht
.insertInterval(interval
);
149 public void finishedBuilding(long endTime
) {
150 sht
.closeTree(endTime
);
151 isFinishedBuilding
= true;
155 public FileInputStream
supplyAttributeTreeReader() {
156 return sht
.supplyATReader();
160 public File
supplyAttributeTreeWriterFile() {
161 return sht
.supplyATWriterFile();
165 public long supplyAttributeTreeWriterFilePosition() {
166 return sht
.supplyATWriterFilePos();
170 public void removeFiles() {
175 public void dispose() {
176 if (isFinishedBuilding
) {
180 * The build is being interrupted, delete the file we partially
181 * built since it won't be complete, so shouldn't be re-used in the
182 * future (.deleteFile() will close the file first)
189 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
)
190 throws TimeRangeException
, StateSystemDisposedException
{
191 if (!checkValidTime(t
)) {
192 /* We can't possibly have information about this query */
193 throw new TimeRangeException();
196 /* We start by reading the information in the root node */
197 HTNode currentNode
= sht
.getRootNode();
198 currentNode
.writeInfoFromNode(stateInfo
, t
);
200 /* Then we follow the branch down in the relevant children */
202 while (currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
203 currentNode
= sht
.selectNextChild((CoreNode
) currentNode
, t
);
204 currentNode
.writeInfoFromNode(stateInfo
, t
);
206 } catch (ClosedChannelException e
) {
207 throw new StateSystemDisposedException(e
);
211 * The stateInfo should now be filled with everything needed, we pass
212 * the control back to the State System.
218 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
219 throws TimeRangeException
, StateSystemDisposedException
{
220 return getRelevantInterval(t
, attributeQuark
);
223 private boolean checkValidTime(long t
) {
224 return (t
>= sht
.getTreeStart() && t
<= sht
.getTreeEnd());
228 * Inner method to find the interval in the tree containing the requested
229 * key/timestamp pair, wherever in which node it is.
233 * @return The node containing the information we want
235 private HTInterval
getRelevantInterval(long t
, int key
)
236 throws TimeRangeException
, StateSystemDisposedException
{
237 if (!checkValidTime(t
)) {
238 throw new TimeRangeException();
241 HTNode currentNode
= sht
.getRootNode();
242 HTInterval interval
= currentNode
.getRelevantInterval(key
, t
);
245 while (interval
== null && currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
246 currentNode
= sht
.selectNextChild((CoreNode
)currentNode
, t
);
247 interval
= currentNode
.getRelevantInterval(key
, t
);
249 } catch (ClosedChannelException e
) {
250 throw new StateSystemDisposedException(e
);
256 * Return the size of the tree history file
258 * @return The current size of the history file in bytes
260 public long getFileSize() {
261 return sht
.getFileSize();
265 * Return the average node usage as a percentage (between 0 and 100)
267 * @return Average node usage %
269 public int getAverageNodeUsage() {
275 for (int seq
= 0; seq
< sht
.getNodeCount(); seq
++) {
276 node
= sht
.readNode(seq
);
277 total
+= node
.getNodeUsagePercent();
279 } catch (ClosedChannelException e
) {
283 ret
= total
/ sht
.getNodeCount();
284 assert (ret
>= 0 && ret
<= 100);
289 public void debugPrint(PrintWriter writer
) {
290 /* By default don't print out all the intervals */
291 this.debugPrint(writer
, false);
295 * The basic debugPrint method will print the tree structure, but not their
298 * This method here print the contents (the intervals) as well.
301 * The PrintWriter to which the debug info will be written
302 * @param printIntervals
303 * Should we also print every contained interval individually?
305 public void debugPrint(PrintWriter writer
, boolean printIntervals
) {
306 /* Only used for debugging, shouldn't be externalized */
307 writer
.println("------------------------------"); //$NON-NLS-1$
308 writer
.println("State History Tree:\n"); //$NON-NLS-1$
309 writer
.println(sht
.toString());
310 writer
.println("Average node utilization: " //$NON-NLS-1$
311 + this.getAverageNodeUsage());
312 writer
.println(""); //$NON-NLS-1$
314 sht
.debugPrintFullTree(writer
, printIntervals
);