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
.internal
.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
.Activator
;
27 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.CoreNode
;
28 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTConfig
;
29 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTInterval
;
30 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTNode
;
31 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HistoryTree
;
32 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
33 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
34 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
35 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
36 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
37 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
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.
43 * @author Alexandre Montplaisir
45 public class HistoryTreeBackend
implements IStateHistoryBackend
{
47 private final @NonNull String fSsid
;
50 * The history tree that sits underneath.
52 private final HistoryTree fSht
;
54 /** Indicates if the history tree construction is done */
55 private volatile boolean fFinishedBuilding
= false;
58 * Indicates if the history tree construction is done
60 * @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
72 protected void setFinishedBuilding(boolean isFinishedBuilding
) {
73 fFinishedBuilding
= isFinishedBuilding
;
77 * Constructor for new history files. Use this when creating a new history
81 * The state system's ID
83 * The filename/location where to store the state history (Should
85 * @param providerVersion
86 * Version of of the state provider. We will only try to reopen
87 * existing files if this version matches the one in the
90 * The earliest time stamp that will be stored in the history
92 * The size of the blocks in the history file. This should be a
95 * The maximum number of children each core node can have
97 * Thrown if we can't create the file for some reason
99 public HistoryTreeBackend(@NonNull String ssid
,
104 int maxChildren
) throws IOException
{
106 final HTConfig conf
= new HTConfig(newStateFile
, blockSize
, maxChildren
,
107 providerVersion
, startTime
);
108 fSht
= new HistoryTree(conf
);
112 * Constructor for new history files. Use this when creating a new history
113 * from scratch. This version supplies sane defaults for the configuration
117 * The state system's id
118 * @param newStateFile
119 * The filename/location where to store the state history (Should
121 * @param providerVersion
122 * Version of of the state provider. We will only try to reopen
123 * existing files if this version matches the one in the
126 * The earliest time stamp that will be stored in the history
127 * @throws IOException
128 * Thrown if we can't create the file for some reason
131 public HistoryTreeBackend(@NonNull String ssid
, File newStateFile
, int providerVersion
, long startTime
)
133 this(ssid
, newStateFile
, providerVersion
, startTime
, 64 * 1024, 50);
137 * Existing history constructor. Use this to open an existing state-file.
140 * The state system's id
141 * @param existingStateFile
142 * Filename/location of the history we want to load
143 * @param providerVersion
144 * Expected version of of the state provider plugin.
145 * @throws IOException
146 * If we can't read the file, if it doesn't exist, is not
147 * recognized, or if the version of the file does not match the
148 * expected providerVersion.
150 public HistoryTreeBackend(@NonNull String ssid
, File existingStateFile
, int providerVersion
)
153 fSht
= new HistoryTree(existingStateFile
, providerVersion
);
154 fFinishedBuilding
= true;
158 * Get the History Tree built by this backend.
160 * @return The history tree
162 protected HistoryTree
getSHT() {
167 public String
getSSID() {
172 public long getStartTime() {
173 return fSht
.getTreeStart();
177 public long getEndTime() {
178 return fSht
.getTreeEnd();
182 public void insertPastState(long stateStartTime
, long stateEndTime
,
183 int quark
, ITmfStateValue value
) throws TimeRangeException
{
184 HTInterval interval
= new HTInterval(stateStartTime
, stateEndTime
,
185 quark
, (TmfStateValue
) value
);
187 /* Start insertions at the "latest leaf" */
188 fSht
.insertInterval(interval
);
192 public void finishedBuilding(long endTime
) {
193 fSht
.closeTree(endTime
);
194 fFinishedBuilding
= true;
198 public FileInputStream
supplyAttributeTreeReader() {
199 return fSht
.supplyATReader();
203 public File
supplyAttributeTreeWriterFile() {
204 return fSht
.supplyATWriterFile();
208 public long supplyAttributeTreeWriterFilePosition() {
209 return fSht
.supplyATWriterFilePos();
213 public void removeFiles() {
218 public void dispose() {
219 if (fFinishedBuilding
) {
223 * The build is being interrupted, delete the file we partially
224 * built since it won't be complete, so shouldn't be re-used in the
225 * future (.deleteFile() will close the file first)
232 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
)
233 throws TimeRangeException
, StateSystemDisposedException
{
236 /* We start by reading the information in the root node */
237 HTNode currentNode
= fSht
.getRootNode();
238 currentNode
.writeInfoFromNode(stateInfo
, t
);
240 /* Then we follow the branch down in the relevant children */
242 while (currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
243 currentNode
= fSht
.selectNextChild((CoreNode
) currentNode
, t
);
244 currentNode
.writeInfoFromNode(stateInfo
, t
);
246 } catch (ClosedChannelException e
) {
247 throw new StateSystemDisposedException(e
);
251 * The stateInfo should now be filled with everything needed, we pass
252 * the control back to the State System.
257 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
258 throws TimeRangeException
, StateSystemDisposedException
{
259 return getRelevantInterval(t
, attributeQuark
);
262 private void checkValidTime(long t
) {
263 long treeStart
= fSht
.getTreeStart();
264 long treeEnd
= fSht
.getTreeEnd();
265 if (t
< treeStart
|| t
> treeEnd
) {
266 throw new TimeRangeException(fSsid
+ " Time:" + t
+ ", Start:" + treeStart
+ ", End:" + treeEnd
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
271 * Inner method to find the interval in the tree containing the requested
272 * key/timestamp pair, wherever in which node it is.
276 * @return The node containing the information we want
278 private HTInterval
getRelevantInterval(long t
, int key
)
279 throws TimeRangeException
, StateSystemDisposedException
{
282 HTNode currentNode
= fSht
.getRootNode();
283 HTInterval interval
= currentNode
.getRelevantInterval(key
, t
);
286 while (interval
== null && currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
287 currentNode
= fSht
.selectNextChild((CoreNode
) currentNode
, t
);
288 interval
= currentNode
.getRelevantInterval(key
, t
);
290 } catch (ClosedChannelException e
) {
291 throw new StateSystemDisposedException(e
);
297 * Return the size of the tree history file
299 * @return The current size of the history file in bytes
301 public long getFileSize() {
302 return fSht
.getFileSize();
306 * Return the average node usage as a percentage (between 0 and 100)
308 * @return Average node usage %
310 public int getAverageNodeUsage() {
316 for (int seq
= 0; seq
< fSht
.getNodeCount(); seq
++) {
317 node
= fSht
.readNode(seq
);
318 total
+= node
.getNodeUsagePercent();
320 } catch (ClosedChannelException e
) {
321 Activator
.getDefault().logError(e
.getMessage(), e
);
324 ret
= total
/ fSht
.getNodeCount();
325 /* The return value should be a percentage */
326 if (ret
< 0 || ret
> 100) {
327 throw new IllegalStateException("Average node usage is not a percentage: " + ret
); //$NON-NLS-1$
333 public void debugPrint(PrintWriter writer
) {
334 /* By default don't print out all the intervals */
335 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(fSht
.toString());
354 writer
.println("Average node utilization: " //$NON-NLS-1$
355 + getAverageNodeUsage());
356 writer
.println(""); //$NON-NLS-1$
358 fSht
.debugPrintFullTree(writer
, printIntervals
);