188c9da8be29dafaefc7492d592b66dafef5781e
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / HistoryTreeBackend.java
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>
5 *
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
10 *
11 * Contributors:
12 * Alexandre Montplaisir - Initial API and implementation
13 * Patrick Tasse - Add message to exceptions
14 *******************************************************************************/
15
16 package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
17
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.IOException;
21 import java.nio.channels.ClosedChannelException;
22 import java.util.List;
23
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;
32
33 import com.google.common.annotations.VisibleForTesting;
34
35 /**
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.
38 *
39 * @author Alexandre Montplaisir
40 */
41 public class HistoryTreeBackend implements IStateHistoryBackend {
42
43 private final @NonNull String fSsid;
44
45 /**
46 * The history tree that sits underneath.
47 */
48 private final @NonNull IHistoryTree fSht;
49
50 /** Indicates if the history tree construction is done */
51 private volatile boolean fFinishedBuilding = false;
52
53 /**
54 * Indicates if the history tree construction is done
55 *
56 * @return if the history tree construction is done
57 */
58 protected boolean isFinishedBuilding() {
59 return fFinishedBuilding;
60 }
61
62 /**
63 * Sets if the history tree is finished building
64 *
65 * @param isFinishedBuilding
66 * is the history tree finished building
67 */
68 protected void setFinishedBuilding(boolean isFinishedBuilding) {
69 fFinishedBuilding = isFinishedBuilding;
70 }
71
72 /**
73 * Constructor for new history files. Use this when creating a new history
74 * from scratch.
75 *
76 * @param ssid
77 * The state system's ID
78 * @param newStateFile
79 * The filename/location where to store the state history (Should
80 * end in .ht)
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
84 * framework.
85 * @param startTime
86 * The earliest time stamp that will be stored in the history
87 * @param blockSize
88 * The size of the blocks in the history file. This should be a
89 * multiple of 4096.
90 * @param maxChildren
91 * The maximum number of children each core node can have
92 * @throws IOException
93 * Thrown if we can't create the file for some reason
94 */
95 public HistoryTreeBackend(@NonNull String ssid,
96 File newStateFile,
97 int providerVersion,
98 long startTime,
99 int blockSize,
100 int maxChildren) throws IOException {
101 fSsid = ssid;
102 final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren,
103 providerVersion, startTime);
104 fSht = initializeSHT(conf);
105 }
106
107 /**
108 * Constructor for new history files. Use this when creating a new history
109 * from scratch. This version supplies sane defaults for the configuration
110 * parameters.
111 *
112 * @param ssid
113 * The state system's id
114 * @param newStateFile
115 * The filename/location where to store the state history (Should
116 * end in .ht)
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
120 * framework.
121 * @param startTime
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
125 * @since 1.0
126 */
127 public HistoryTreeBackend(@NonNull String ssid, File newStateFile, int providerVersion, long startTime)
128 throws IOException {
129 this(ssid, newStateFile, providerVersion, startTime, 64 * 1024, 50);
130 }
131
132 /**
133 * Existing history constructor. Use this to open an existing state-file.
134 *
135 * @param ssid
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.
145 */
146 public HistoryTreeBackend(@NonNull String ssid, @NonNull File existingStateFile, int providerVersion)
147 throws IOException {
148 fSsid = ssid;
149 fSht = initializeSHT(existingStateFile, providerVersion);
150 fFinishedBuilding = true;
151 }
152
153 /**
154 * New-tree initializer for the History Tree wrapped by this backend. Can be
155 * overriden to use different implementations.
156 *
157 * @param conf
158 * The HTConfig configuration object
159 * @return The new history tree
160 * @throws IOException
161 * If there was a problem during creation
162 */
163 @VisibleForTesting
164 protected @NonNull IHistoryTree initializeSHT(@NonNull HTConfig conf) throws IOException {
165 return HistoryTreeFactory.createHistoryTree(conf);
166 }
167
168 /**
169 * Existing-tree initializer for the History Tree wrapped by this backend.
170 * Can be overriden to use different implementations.
171 *
172 * @param existingStateFile
173 * The file to open
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
179 */
180 @VisibleForTesting
181 protected @NonNull IHistoryTree initializeSHT(@NonNull File existingStateFile, int providerVersion) throws IOException {
182 return HistoryTreeFactory.createFromFile(existingStateFile.toPath(), providerVersion);
183 }
184
185 /**
186 * Get the History Tree built by this backend.
187 *
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.
191 *
192 * @return The history tree
193 */
194 protected final @NonNull IHistoryTree getSHT() {
195 return fSht;
196 }
197
198 @Override
199 public String getSSID() {
200 return fSsid;
201 }
202
203 @Override
204 public long getStartTime() {
205 return getSHT().getTreeStart();
206 }
207
208 @Override
209 public long getEndTime() {
210 return getSHT().getTreeEnd();
211 }
212
213 @Override
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);
218
219 /* Start insertions at the "latest leaf" */
220 getSHT().insertInterval(interval);
221 }
222
223 @Override
224 public void finishedBuilding(long endTime) {
225 getSHT().closeTree(endTime);
226 fFinishedBuilding = true;
227 }
228
229 @Override
230 public FileInputStream supplyAttributeTreeReader() {
231 return getSHT().supplyATReader();
232 }
233
234 @Override
235 public File supplyAttributeTreeWriterFile() {
236 return getSHT().supplyATWriterFile();
237 }
238
239 @Override
240 public long supplyAttributeTreeWriterFilePosition() {
241 return getSHT().supplyATWriterFilePos();
242 }
243
244 @Override
245 public void removeFiles() {
246 getSHT().deleteFile();
247 }
248
249 @Override
250 public void dispose() {
251 if (fFinishedBuilding) {
252 getSHT().closeFile();
253 } else {
254 /*
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)
258 */
259 getSHT().deleteFile();
260 }
261 }
262
263 @Override
264 public void doQuery(List<ITmfStateInterval> stateInfo, long t)
265 throws TimeRangeException, StateSystemDisposedException {
266 checkValidTime(t);
267
268 /* We start by reading the information in the root node */
269 HTNode currentNode = getSHT().getRootNode();
270 currentNode.writeInfoFromNode(stateInfo, t);
271
272 /* Then we follow the branch down in the relevant children */
273 try {
274 while (currentNode.getNodeType() == HTNode.NodeType.CORE) {
275 currentNode = getSHT().selectNextChild((CoreNode) currentNode, t);
276 currentNode.writeInfoFromNode(stateInfo, t);
277 }
278 } catch (ClosedChannelException e) {
279 throw new StateSystemDisposedException(e);
280 }
281
282 /*
283 * The stateInfo should now be filled with everything needed, we pass
284 * the control back to the State System.
285 */
286 }
287
288 @Override
289 public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
290 throws TimeRangeException, StateSystemDisposedException {
291 return getRelevantInterval(t, attributeQuark);
292 }
293
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));
300 }
301 }
302
303 /**
304 * Inner method to find the interval in the tree containing the requested
305 * key/timestamp pair, wherever in which node it is.
306 *
307 * @param t
308 * @param key
309 * @return The node containing the information we want
310 */
311 private HTInterval getRelevantInterval(long t, int key)
312 throws TimeRangeException, StateSystemDisposedException {
313 checkValidTime(t);
314
315 HTNode currentNode = getSHT().getRootNode();
316 HTInterval interval = currentNode.getRelevantInterval(key, t);
317
318 try {
319 while (interval == null && currentNode.getNodeType() == HTNode.NodeType.CORE) {
320 currentNode = getSHT().selectNextChild((CoreNode) currentNode, t);
321 interval = currentNode.getRelevantInterval(key, t);
322 }
323 } catch (ClosedChannelException e) {
324 throw new StateSystemDisposedException(e);
325 }
326 return interval;
327 }
328
329 /**
330 * Return the size of the tree history file
331 *
332 * @return The current size of the history file in bytes
333 */
334 public long getFileSize() {
335 return getSHT().getFileSize();
336 }
337
338 /**
339 * Return the average node usage as a percentage (between 0 and 100)
340 *
341 * @return Average node usage %
342 */
343 public int getAverageNodeUsage() {
344 HTNode node;
345 long total = 0;
346 long ret;
347
348 try {
349 for (int seq = 0; seq < getSHT().getNodeCount(); seq++) {
350 node = getSHT().readNode(seq);
351 total += node.getNodeUsagePercent();
352 }
353 } catch (ClosedChannelException e) {
354 Activator.getDefault().logError(e.getMessage(), e);
355 }
356
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$
361 }
362 return (int) ret;
363 }
364
365 }
This page took 0.039711 seconds and 5 git commands to generate.