1 /*******************************************************************************
2 * Copyright (c) 2012 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
.linuxtools
.internal
.tmf
.core
.statesystem
.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
.linuxtools
.internal
.tmf
.core
.statesystem
.IStateHistoryBackend
;
23 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateSystemDisposedException
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.ITmfStateValue
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.statevalue
.TmfStateValue
;
30 * History Tree backend for storing a state history. This is the basic version
31 * that runs in the same thread as the class creating it.
36 public class HistoryTreeBackend
implements IStateHistoryBackend
{
38 protected final HistoryTree sht
;
39 private final HT_IO treeIO
;
41 /** Indicates if the history tree construction is done */
42 protected boolean isFinishedBuilding
= false;
45 * Construtor for new history files. Use this when creating a new history
49 * The filename/location where to store the state history (Should
52 * The size of the blocks in the history file. This should be a
55 * The maximum number of children each core node can have
57 * The earliest time stamp that will be stored in the history
59 * Thrown if we can't create the file for some reason
61 public HistoryTreeBackend(File newStateFile
, int blockSize
,
62 int maxChildren
, long startTime
) throws IOException
{
63 sht
= new HistoryTree(newStateFile
, blockSize
, maxChildren
, startTime
);
64 treeIO
= sht
.getTreeIO();
68 * Construtor for new history files. Use this when creating a new history
69 * from scratch. This version supplies sane defaults for the configuration
73 * The filename/location where to store the state history (Should
76 * The earliest time stamp that will be stored in the history
78 * Thrown if we can't create the file for some reason
80 public HistoryTreeBackend(File newStateFile
, long startTime
)
82 this(newStateFile
, 64 * 1024, 50, startTime
);
86 * Existing history constructor. Use this to open an existing state-file.
88 * @param existingStateFile
89 * Filename/location of the history we want to load
91 * If we can't read the file, if it doesn't exist or is not
94 public HistoryTreeBackend(File existingStateFile
) throws IOException
{
95 sht
= new HistoryTree(existingStateFile
);
96 treeIO
= sht
.getTreeIO();
97 isFinishedBuilding
= true;
101 public long getStartTime() {
102 return sht
.getTreeStart();
106 public long getEndTime() {
107 return sht
.getTreeEnd();
111 public void insertPastState(long stateStartTime
, long stateEndTime
,
112 int quark
, ITmfStateValue value
) throws TimeRangeException
{
113 HTInterval interval
= new HTInterval(stateStartTime
, stateEndTime
,
114 quark
, (TmfStateValue
) value
);
116 /* Start insertions at the "latest leaf" */
117 sht
.insertInterval(interval
);
121 public void finishedBuilding(long endTime
) {
122 sht
.closeTree(endTime
);
123 isFinishedBuilding
= true;
127 public FileInputStream
supplyAttributeTreeReader() {
128 return treeIO
.supplyATReader();
132 public File
supplyAttributeTreeWriterFile() {
133 return treeIO
.supplyATWriterFile();
137 public long supplyAttributeTreeWriterFilePosition() {
138 return treeIO
.supplyATWriterFilePos();
142 public void removeFiles() {
147 public void dispose() {
148 if (isFinishedBuilding
) {
152 * The build is being interrupted, delete the file we partially
153 * built since it won't be complete, so shouldn't be re-used in the
154 * future (.deleteFile() will close the file first)
161 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
)
162 throws TimeRangeException
, StateSystemDisposedException
{
163 if (!checkValidTime(t
)) {
164 /* We can't possibly have information about this query */
165 throw new TimeRangeException();
168 /* We start by reading the information in the root node */
169 // FIXME using CoreNode for now, we'll have to redo this part to handle
170 // different node types
171 CoreNode currentNode
= sht
.latestBranch
.firstElement();
172 currentNode
.writeInfoFromNode(stateInfo
, t
);
174 /* Then we follow the branch down in the relevant children */
176 while (currentNode
.getNbChildren() > 0) {
177 currentNode
= (CoreNode
) sht
.selectNextChild(currentNode
, t
);
178 currentNode
.writeInfoFromNode(stateInfo
, t
);
180 } catch (ClosedChannelException e
) {
181 throw new StateSystemDisposedException();
185 * The stateInfo should now be filled with everything needed, we pass
186 * the control back to the State System.
192 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
193 throws TimeRangeException
, StateSystemDisposedException
{
194 return getRelevantInterval(t
, attributeQuark
);
198 public boolean checkValidTime(long t
) {
199 return (t
>= sht
.getTreeStart() && t
<= sht
.getTreeEnd());
203 * Inner method to find the interval in the tree containing the requested
204 * key/timestamp pair, wherever in which node it is.
208 * @return The node containing the information we want
210 private HTInterval
getRelevantInterval(long t
, int key
)
211 throws TimeRangeException
, StateSystemDisposedException
{
212 if (!checkValidTime(t
)) {
213 throw new TimeRangeException();
216 // FIXME using CoreNode for now, we'll have to redo this part to handle
217 // different node types
218 CoreNode currentNode
= sht
.latestBranch
.firstElement();
219 HTInterval interval
= currentNode
.getRelevantInterval(key
, t
);
222 while (interval
== null && currentNode
.getNbChildren() > 0) {
223 currentNode
= (CoreNode
) sht
.selectNextChild(currentNode
, t
);
224 interval
= currentNode
.getRelevantInterval(key
, t
);
226 } catch (ClosedChannelException e
) {
227 throw new StateSystemDisposedException();
230 * Since we should now have intervals at every attribute/timestamp
231 * combination, it should NOT be null here.
233 assert (interval
!= null);
238 * Return the size of the tree history file
240 * @return The current size of the history file in bytes
242 public long getFileSize() {
243 return sht
.getFileSize();
247 * Return the current depth of the tree, ie the number of node levels.
249 * @return The tree depth
251 public int getTreeDepth() {
252 return sht
.latestBranch
.size();
256 * Return the average node usage as a percentage (between 0 and 100)
258 * @return Average node usage %
260 public int getAverageNodeUsage() {
266 for (int seq
= 0; seq
< sht
.getNodeCount(); seq
++) {
267 node
= treeIO
.readNode(seq
);
268 total
+= node
.getNodeUsagePRC();
270 } catch (ClosedChannelException e
) {
274 ret
= total
/ sht
.getNodeCount();
275 assert (ret
>= 0 && ret
<= 100);
280 public void debugPrint(PrintWriter writer
) {
281 /* By default don't print out all the intervals */
282 this.debugPrint(writer
, false);
286 * The basic debugPrint method will print the tree structure, but not their
289 * This method here print the contents (the intervals) as well.
292 * The PrintWriter to which the debug info will be written
293 * @param printIntervals
294 * Should we also print every contained interval individually?
296 public void debugPrint(PrintWriter writer
, boolean printIntervals
) {
297 /* Only used for debugging, shouldn't be externalized */
298 writer
.println("------------------------------"); //$NON-NLS-1$
299 writer
.println("State History Tree:\n"); //$NON-NLS-1$
300 writer
.println(sht
.toString());
301 writer
.println("Average node utilization: " //$NON-NLS-1$
302 + this.getAverageNodeUsage());
303 writer
.println(""); //$NON-NLS-1$
305 sht
.debugPrintFullTree(writer
, printIntervals
);