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 /** The history tree that sits underneath */
39 protected final HistoryTree sht
;
41 /** Direct reference to the tree's IO object */
42 private final HT_IO treeIO
;
44 /** Indicates if the history tree construction is done */
45 protected boolean isFinishedBuilding
= false;
48 * Construtor for new history files. Use this when creating a new history
52 * The filename/location where to store the state history (Should
55 * The size of the blocks in the history file. This should be a
58 * The maximum number of children each core node can have
60 * The earliest time stamp that will be stored in the history
62 * Thrown if we can't create the file for some reason
64 public HistoryTreeBackend(File newStateFile
, int blockSize
,
65 int maxChildren
, long startTime
) throws IOException
{
66 sht
= new HistoryTree(newStateFile
, blockSize
, maxChildren
, startTime
);
67 treeIO
= sht
.getTreeIO();
71 * Construtor for new history files. Use this when creating a new history
72 * from scratch. This version supplies sane defaults for the configuration
76 * The filename/location where to store the state history (Should
79 * The earliest time stamp that will be stored in the history
81 * Thrown if we can't create the file for some reason
83 public HistoryTreeBackend(File newStateFile
, long startTime
)
85 this(newStateFile
, 64 * 1024, 50, startTime
);
89 * Existing history constructor. Use this to open an existing state-file.
91 * @param existingStateFile
92 * Filename/location of the history we want to load
94 * If we can't read the file, if it doesn't exist or is not
97 public HistoryTreeBackend(File existingStateFile
) throws IOException
{
98 sht
= new HistoryTree(existingStateFile
);
99 treeIO
= sht
.getTreeIO();
100 isFinishedBuilding
= true;
104 public long getStartTime() {
105 return sht
.getTreeStart();
109 public long getEndTime() {
110 return sht
.getTreeEnd();
114 public void insertPastState(long stateStartTime
, long stateEndTime
,
115 int quark
, ITmfStateValue value
) throws TimeRangeException
{
116 HTInterval interval
= new HTInterval(stateStartTime
, stateEndTime
,
117 quark
, (TmfStateValue
) value
);
119 /* Start insertions at the "latest leaf" */
120 sht
.insertInterval(interval
);
124 public void finishedBuilding(long endTime
) {
125 sht
.closeTree(endTime
);
126 isFinishedBuilding
= true;
130 public FileInputStream
supplyAttributeTreeReader() {
131 return treeIO
.supplyATReader();
135 public File
supplyAttributeTreeWriterFile() {
136 return treeIO
.supplyATWriterFile();
140 public long supplyAttributeTreeWriterFilePosition() {
141 return treeIO
.supplyATWriterFilePos();
145 public void removeFiles() {
150 public void dispose() {
151 if (isFinishedBuilding
) {
155 * The build is being interrupted, delete the file we partially
156 * built since it won't be complete, so shouldn't be re-used in the
157 * future (.deleteFile() will close the file first)
164 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
)
165 throws TimeRangeException
, StateSystemDisposedException
{
166 if (!checkValidTime(t
)) {
167 /* We can't possibly have information about this query */
168 throw new TimeRangeException();
171 /* We start by reading the information in the root node */
172 // FIXME using CoreNode for now, we'll have to redo this part to handle
173 // different node types
174 CoreNode currentNode
= sht
.latestBranch
.firstElement();
175 currentNode
.writeInfoFromNode(stateInfo
, t
);
177 /* Then we follow the branch down in the relevant children */
179 while (currentNode
.getNbChildren() > 0) {
180 currentNode
= (CoreNode
) sht
.selectNextChild(currentNode
, t
);
181 currentNode
.writeInfoFromNode(stateInfo
, t
);
183 } catch (ClosedChannelException e
) {
184 throw new StateSystemDisposedException();
188 * The stateInfo should now be filled with everything needed, we pass
189 * the control back to the State System.
195 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
196 throws TimeRangeException
, StateSystemDisposedException
{
197 return getRelevantInterval(t
, attributeQuark
);
201 public boolean checkValidTime(long t
) {
202 return (t
>= sht
.getTreeStart() && t
<= sht
.getTreeEnd());
206 * Inner method to find the interval in the tree containing the requested
207 * key/timestamp pair, wherever in which node it is.
211 * @return The node containing the information we want
213 private HTInterval
getRelevantInterval(long t
, int key
)
214 throws TimeRangeException
, StateSystemDisposedException
{
215 if (!checkValidTime(t
)) {
216 throw new TimeRangeException();
219 // FIXME using CoreNode for now, we'll have to redo this part to handle
220 // different node types
221 CoreNode currentNode
= sht
.latestBranch
.firstElement();
222 HTInterval interval
= currentNode
.getRelevantInterval(key
, t
);
225 while (interval
== null && currentNode
.getNbChildren() > 0) {
226 currentNode
= (CoreNode
) sht
.selectNextChild(currentNode
, t
);
227 interval
= currentNode
.getRelevantInterval(key
, t
);
229 } catch (ClosedChannelException e
) {
230 throw new StateSystemDisposedException();
233 * Since we should now have intervals at every attribute/timestamp
234 * combination, it should NOT be null here.
236 assert (interval
!= null);
241 * Return the size of the tree history file
243 * @return The current size of the history file in bytes
245 public long getFileSize() {
246 return sht
.getFileSize();
250 * Return the current depth of the tree, ie the number of node levels.
252 * @return The tree depth
254 public int getTreeDepth() {
255 return sht
.latestBranch
.size();
259 * Return the average node usage as a percentage (between 0 and 100)
261 * @return Average node usage %
263 public int getAverageNodeUsage() {
269 for (int seq
= 0; seq
< sht
.getNodeCount(); seq
++) {
270 node
= treeIO
.readNode(seq
);
271 total
+= node
.getNodeUsagePRC();
273 } catch (ClosedChannelException e
) {
277 ret
= total
/ sht
.getNodeCount();
278 assert (ret
>= 0 && ret
<= 100);
283 public void debugPrint(PrintWriter writer
) {
284 /* By default don't print out all the intervals */
285 this.debugPrint(writer
, false);
289 * The basic debugPrint method will print the tree structure, but not their
292 * This method here print the contents (the intervals) as well.
295 * The PrintWriter to which the debug info will be written
296 * @param printIntervals
297 * Should we also print every contained interval individually?
299 public void debugPrint(PrintWriter writer
, boolean printIntervals
) {
300 /* Only used for debugging, shouldn't be externalized */
301 writer
.println("------------------------------"); //$NON-NLS-1$
302 writer
.println("State History Tree:\n"); //$NON-NLS-1$
303 writer
.println(sht
.toString());
304 writer
.println("Average node utilization: " //$NON-NLS-1$
305 + this.getAverageNodeUsage());
306 writer
.println(""); //$NON-NLS-1$
308 sht
.debugPrintFullTree(writer
, printIntervals
);