1 /*******************************************************************************
2 * Copyright (c) 2012, 2016 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
.nio
.channels
.ClosedChannelException
;
22 import java
.util
.List
;
24 import org
.eclipse
.jdt
.annotation
.NonNull
;
25 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.Activator
;
26 import org
.eclipse
.tracecompass
.statesystem
.core
.backend
.IStateHistoryBackend
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
28 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
29 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
30 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
31 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
33 import com
.google
.common
.annotations
.VisibleForTesting
;
36 * History Tree backend for storing a state history. This is the basic version
37 * that runs in the same thread as the class creating it.
39 * @author Alexandre Montplaisir
41 public class HistoryTreeBackend
implements IStateHistoryBackend
{
43 private final @NonNull String fSsid
;
46 * The history tree that sits underneath.
48 private final @NonNull IHistoryTree fSht
;
50 /** Indicates if the history tree construction is done */
51 private volatile boolean fFinishedBuilding
= false;
54 * Indicates if the history tree construction is done
56 * @return if the history tree construction is done
58 protected boolean isFinishedBuilding() {
59 return fFinishedBuilding
;
63 * Sets if the history tree is finished building
65 * @param isFinishedBuilding
66 * is the history tree finished building
68 protected void setFinishedBuilding(boolean isFinishedBuilding
) {
69 fFinishedBuilding
= isFinishedBuilding
;
73 * Constructor for new history files. Use this when creating a new history
77 * The state system's ID
79 * The filename/location where to store the state history (Should
81 * @param providerVersion
82 * Version of of the state provider. We will only try to reopen
83 * existing files if this version matches the one in the
86 * The earliest time stamp that will be stored in the history
88 * The size of the blocks in the history file. This should be a
91 * The maximum number of children each core node can have
93 * Thrown if we can't create the file for some reason
95 public HistoryTreeBackend(@NonNull String ssid
,
100 int maxChildren
) throws IOException
{
102 final HTConfig conf
= new HTConfig(newStateFile
, blockSize
, maxChildren
,
103 providerVersion
, startTime
);
104 fSht
= initializeSHT(conf
);
108 * Constructor for new history files. Use this when creating a new history
109 * from scratch. This version supplies sane defaults for the configuration
113 * The state system's id
114 * @param newStateFile
115 * The filename/location where to store the state history (Should
117 * @param providerVersion
118 * Version of of the state provider. We will only try to reopen
119 * existing files if this version matches the one in the
122 * The earliest time stamp that will be stored in the history
123 * @throws IOException
124 * Thrown if we can't create the file for some reason
127 public HistoryTreeBackend(@NonNull String ssid
, File newStateFile
, int providerVersion
, long startTime
)
129 this(ssid
, newStateFile
, providerVersion
, startTime
, 64 * 1024, 50);
133 * Existing history constructor. Use this to open an existing state-file.
136 * The state system's id
137 * @param existingStateFile
138 * Filename/location of the history we want to load
139 * @param providerVersion
140 * Expected version of of the state provider plugin.
141 * @throws IOException
142 * If we can't read the file, if it doesn't exist, is not
143 * recognized, or if the version of the file does not match the
144 * expected providerVersion.
146 public HistoryTreeBackend(@NonNull String ssid
, @NonNull File existingStateFile
, int providerVersion
)
149 fSht
= initializeSHT(existingStateFile
, providerVersion
);
150 fFinishedBuilding
= true;
154 * New-tree initializer for the History Tree wrapped by this backend. Can be
155 * overriden to use different implementations.
158 * The HTConfig configuration object
159 * @return The new history tree
160 * @throws IOException
161 * If there was a problem during creation
164 protected @NonNull IHistoryTree
initializeSHT(@NonNull HTConfig conf
) throws IOException
{
165 return HistoryTreeFactory
.createHistoryTree(conf
);
169 * Existing-tree initializer for the History Tree wrapped by this backend.
170 * Can be overriden to use different implementations.
172 * @param existingStateFile
174 * @param providerVersion
175 * The expected state provider version
176 * @return The history tree opened from the given file
177 * @throws IOException
178 * If there was a problem during creation
181 protected @NonNull IHistoryTree
initializeSHT(@NonNull File existingStateFile
, int providerVersion
) throws IOException
{
182 return HistoryTreeFactory
.createFromFile(existingStateFile
.toPath(), providerVersion
);
186 * Get the History Tree built by this backend.
188 * Note: Do not override this method. If you want to extend the class to use
189 * a different History Tree implementation, override both variants of
190 * {@link #initializeSHT} instead.
192 * @return The history tree
194 protected final @NonNull IHistoryTree
getSHT() {
199 public String
getSSID() {
204 public long getStartTime() {
205 return getSHT().getTreeStart();
209 public long getEndTime() {
210 return getSHT().getTreeEnd();
214 public void insertPastState(long stateStartTime
, long stateEndTime
,
215 int quark
, ITmfStateValue value
) throws TimeRangeException
{
216 HTInterval interval
= new HTInterval(stateStartTime
, stateEndTime
,
217 quark
, (TmfStateValue
) value
);
219 /* Start insertions at the "latest leaf" */
220 getSHT().insertInterval(interval
);
224 public void finishedBuilding(long endTime
) {
225 getSHT().closeTree(endTime
);
226 fFinishedBuilding
= true;
230 public FileInputStream
supplyAttributeTreeReader() {
231 return getSHT().supplyATReader();
235 public File
supplyAttributeTreeWriterFile() {
236 return getSHT().supplyATWriterFile();
240 public long supplyAttributeTreeWriterFilePosition() {
241 return getSHT().supplyATWriterFilePos();
245 public void removeFiles() {
246 getSHT().deleteFile();
250 public void dispose() {
251 if (fFinishedBuilding
) {
252 getSHT().closeFile();
255 * The build is being interrupted, delete the file we partially
256 * built since it won't be complete, so shouldn't be re-used in the
257 * future (.deleteFile() will close the file first)
259 getSHT().deleteFile();
264 public void doQuery(List
<ITmfStateInterval
> stateInfo
, long t
)
265 throws TimeRangeException
, StateSystemDisposedException
{
268 /* We start by reading the information in the root node */
269 HTNode currentNode
= getSHT().getRootNode();
270 currentNode
.writeInfoFromNode(stateInfo
, t
);
272 /* Then we follow the branch down in the relevant children */
274 while (currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
275 currentNode
= getSHT().selectNextChild((CoreNode
) currentNode
, t
);
276 currentNode
.writeInfoFromNode(stateInfo
, t
);
278 } catch (ClosedChannelException e
) {
279 throw new StateSystemDisposedException(e
);
283 * The stateInfo should now be filled with everything needed, we pass
284 * the control back to the State System.
289 public ITmfStateInterval
doSingularQuery(long t
, int attributeQuark
)
290 throws TimeRangeException
, StateSystemDisposedException
{
291 return getRelevantInterval(t
, attributeQuark
);
294 private void checkValidTime(long t
) {
295 long startTime
= getStartTime();
296 long endTime
= getEndTime();
297 if (t
< startTime
|| t
> endTime
) {
298 throw new TimeRangeException(String
.format("%s Time:%d, Start:%d, End:%d", //$NON-NLS-1$
299 fSsid
, t
, startTime
, endTime
));
304 * Inner method to find the interval in the tree containing the requested
305 * key/timestamp pair, wherever in which node it is.
309 * @return The node containing the information we want
311 private HTInterval
getRelevantInterval(long t
, int key
)
312 throws TimeRangeException
, StateSystemDisposedException
{
315 HTNode currentNode
= getSHT().getRootNode();
316 HTInterval interval
= currentNode
.getRelevantInterval(key
, t
);
319 while (interval
== null && currentNode
.getNodeType() == HTNode
.NodeType
.CORE
) {
320 currentNode
= getSHT().selectNextChild((CoreNode
) currentNode
, t
);
321 interval
= currentNode
.getRelevantInterval(key
, t
);
323 } catch (ClosedChannelException e
) {
324 throw new StateSystemDisposedException(e
);
330 * Return the size of the tree history file
332 * @return The current size of the history file in bytes
334 public long getFileSize() {
335 return getSHT().getFileSize();
339 * Return the average node usage as a percentage (between 0 and 100)
341 * @return Average node usage %
343 public int getAverageNodeUsage() {
349 for (int seq
= 0; seq
< getSHT().getNodeCount(); seq
++) {
350 node
= getSHT().readNode(seq
);
351 total
+= node
.getNodeUsagePercent();
353 } catch (ClosedChannelException e
) {
354 Activator
.getDefault().logError(e
.getMessage(), e
);
357 ret
= total
/ getSHT().getNodeCount();
358 /* The return value should be a percentage */
359 if (ret
< 0 || ret
> 100) {
360 throw new IllegalStateException("Average node usage is not a percentage: " + ret
); //$NON-NLS-1$