common: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / ThreadedHistoryTreeBackend.java
CommitLineData
a52fde77 1/*******************************************************************************
b2f62cb5 2 * Copyright (c) 2012, 2015 Ericsson
a52fde77
AM
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
1a4205d9 5 *
a52fde77
AM
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
1a4205d9 10 *
b2f62cb5
AM
11 * Contributors:
12 * Alexandre Montplaisir - Initial API and implementation
a52fde77
AM
13 *******************************************************************************/
14
0306a843 15package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
a52fde77
AM
16
17import java.io.File;
18import java.io.IOException;
e62a23a9 19import java.util.List;
a52fde77 20
e62a23a9 21import org.eclipse.jdt.annotation.NonNull;
f00251b5 22import org.eclipse.tracecompass.common.core.collect.BufferedBlockingQueue;
e894a508 23import org.eclipse.tracecompass.internal.statesystem.core.Activator;
e62a23a9 24import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
e894a508 25import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
e62a23a9 26import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
e894a508
AM
27import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
28import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
a52fde77
AM
29
30/**
31 * Variant of the HistoryTreeBackend which runs all the interval-insertion logic
32 * in a separate thread.
1a4205d9 33 *
bcec0116 34 * @author Alexandre Montplaisir
a52fde77 35 */
ab604305
AM
36public final class ThreadedHistoryTreeBackend extends HistoryTreeBackend
37 implements Runnable {
a52fde77 38
f00251b5
AM
39 private static final int CHUNK_SIZE = 127;
40 private final @NonNull BufferedBlockingQueue<HTInterval> intervalQueue;
e62a23a9 41 private final @NonNull Thread shtThread;
a52fde77
AM
42
43 /**
44 * New state history constructor
1a4205d9 45 *
a52fde77
AM
46 * Note that it usually doesn't make sense to use a Threaded HT if you're
47 * opening an existing state-file, but you know what you're doing...
1a4205d9 48 *
b2f62cb5
AM
49 * @param ssid
50 * The state system's id
a52fde77
AM
51 * @param newStateFile
52 * The name of the history file that will be created. Should end
53 * in ".ht"
a96cc6be
AM
54 * @param providerVersion
55 * Version of of the state provider. We will only try to reopen
56 * existing files if this version matches the one in the
57 * framework.
f6d24a71
AM
58 * @param startTime
59 * The earliest timestamp stored in the history
a52fde77
AM
60 * @param queueSize
61 * The size of the interval insertion queue. 2000 - 10000 usually
62 * works well
f6d24a71
AM
63 * @param blockSize
64 * The size of the blocks in the file
65 * @param maxChildren
66 * The maximum number of children allowed for each core node
a52fde77
AM
67 * @throws IOException
68 * If there was a problem opening the history file for writing
69 */
f6d24a71
AM
70 public ThreadedHistoryTreeBackend(@NonNull String ssid,
71 File newStateFile,
72 int providerVersion,
73 long startTime,
74 int queueSize,
75 int blockSize,
76 int maxChildren)
4cdea8fc 77 throws IOException {
f6d24a71 78 super(ssid, newStateFile, providerVersion, startTime, blockSize, maxChildren);
a52fde77 79
f00251b5 80 intervalQueue = new BufferedBlockingQueue<>(queueSize / CHUNK_SIZE, CHUNK_SIZE);
a52fde77
AM
81 shtThread = new Thread(this, "History Tree Thread"); //$NON-NLS-1$
82 shtThread.start();
83 }
84
85 /**
86 * New State History constructor. This version provides default values for
87 * blockSize and maxChildren.
1a4205d9 88 *
b2f62cb5
AM
89 * @param ssid
90 * The state system's id
a52fde77
AM
91 * @param newStateFile
92 * The name of the history file that will be created. Should end
93 * in ".ht"
a96cc6be
AM
94 * @param providerVersion
95 * Version of of the state provider. We will only try to reopen
96 * existing files if this version matches the one in the
97 * framework.
f6d24a71
AM
98 * @param startTime
99 * The earliest timestamp stored in the history
a52fde77
AM
100 * @param queueSize
101 * The size of the interval insertion queue. 2000 - 10000 usually
102 * works well
103 * @throws IOException
104 * If there was a problem opening the history file for writing
105 */
f6d24a71
AM
106 public ThreadedHistoryTreeBackend(@NonNull String ssid,
107 File newStateFile,
108 int providerVersion,
109 long startTime,
110 int queueSize)
4cdea8fc 111 throws IOException {
b2f62cb5 112 super(ssid, newStateFile, providerVersion, startTime);
a52fde77 113
f00251b5 114 intervalQueue = new BufferedBlockingQueue<>(queueSize / CHUNK_SIZE, CHUNK_SIZE);
a52fde77
AM
115 shtThread = new Thread(this, "History Tree Thread"); //$NON-NLS-1$
116 shtThread.start();
117 }
118
119 /*
120 * The Threaded version does not specify an "existing file" constructor,
121 * since the history is already built (and we only use the other thread
122 * during building). Just use a plain HistoryTreeProvider in this case.
1a4205d9 123 *
a52fde77
AM
124 * TODO but what about streaming??
125 */
126
127 @Override
128 public void insertPastState(long stateStartTime, long stateEndTime,
129 int quark, ITmfStateValue value) throws TimeRangeException {
130 /*
131 * Here, instead of directly inserting the elements in the History Tree
132 * underneath, we'll put them in the Queue. They will then be taken and
133 * processed by the other thread executing the run() method.
134 */
4cdea8fc
MK
135 HTInterval interval = new HTInterval(stateStartTime, stateEndTime,
136 quark, (TmfStateValue) value);
f00251b5 137 intervalQueue.put(interval);
a52fde77
AM
138 }
139
140 @Override
b33c7369 141 public void finishedBuilding(long endTime) {
a52fde77
AM
142 /*
143 * We need to commit everything in the History Tree and stop the
144 * standalone thread before returning to the StateHistorySystem. (SHS
145 * will then write the Attribute Tree to the file, that must not happen
146 * at the same time we are writing the last nodes!)
147 */
148
1a4205d9 149 stopRunningThread(endTime);
d740e018 150 setFinishedBuilding(true);
1a4205d9
AM
151 return;
152 }
153
154 @Override
155 public void dispose() {
d740e018 156 if (!isFinishedBuilding()) {
bcec0116 157 stopRunningThread(Long.MAX_VALUE);
1a4205d9 158 }
a52fde77 159 /*
1a4205d9
AM
160 * isFinishedBuilding remains false, so the superclass will ask the
161 * back-end to delete the file.
162 */
163 super.dispose();
164 }
165
166 private void stopRunningThread(long endTime) {
167 if (!shtThread.isAlive()) {
168 return;
169 }
170
171 /*
d740e018
MK
172 * Send a "poison pill" in the queue, then wait for the HT to finish its
173 * closeTree()
a52fde77
AM
174 */
175 try {
4cdea8fc 176 HTInterval pill = new HTInterval(-1, endTime, -1, TmfStateValue.nullValue());
b33c7369 177 intervalQueue.put(pill);
f00251b5 178 intervalQueue.flushInputBuffer();
a52fde77 179 shtThread.join();
b33c7369 180 } catch (TimeRangeException e) {
bcec0116 181 Activator.getDefault().logError("Error closing state system", e); //$NON-NLS-1$
a52fde77 182 } catch (InterruptedException e) {
bcec0116 183 Activator.getDefault().logError("State system interrupted", e); //$NON-NLS-1$
a52fde77 184 }
a52fde77
AM
185 }
186
187 @Override
188 public void run() {
4cdea8fc 189 HTInterval currentInterval;
a52fde77 190 try {
4cdea8fc
MK
191 currentInterval = intervalQueue.take();
192 while (currentInterval.getStartTime() != -1) {
193 /* Send the interval to the History Tree */
194 getSHT().insertInterval(currentInterval);
195 currentInterval = intervalQueue.take();
196 }
197 if (currentInterval.getAttribute() != -1) {
198 /* Make sure this is the "poison pill" we are waiting for */
199 throw new IllegalStateException();
e62a23a9 200 }
4cdea8fc
MK
201 /*
202 * We've been told we're done, let's write down everything and quit.
203 * The end time of this "signal interval" is actually correct.
204 */
205 getSHT().closeTree(currentInterval.getEndTime());
206 return;
a52fde77 207 } catch (TimeRangeException e) {
f00251b5 208 /* This should not happen */
bcec0116 209 Activator.getDefault().logError("Error starting the state system", e); //$NON-NLS-1$
a52fde77
AM
210 }
211 }
212
e62a23a9
AM
213 // ------------------------------------------------------------------------
214 // Query methods
215 // ------------------------------------------------------------------------
216
217 @Override
218 public void doQuery(List<ITmfStateInterval> currentStateInfo, long t)
219 throws TimeRangeException, StateSystemDisposedException {
220 super.doQuery(currentStateInfo, t);
221
d740e018 222 if (isFinishedBuilding()) {
e62a23a9
AM
223 /*
224 * The history tree is the only place to look for intervals once
225 * construction is finished.
226 */
227 return;
228 }
229
230 /*
231 * It is possible we may have missed some intervals due to them being in
232 * the queue while the query was ongoing. Go over the results to see if
233 * we missed any.
234 */
235 for (int i = 0; i < currentStateInfo.size(); i++) {
236 if (currentStateInfo.get(i) == null) {
237 /* Query the missing interval via "unicast" */
238 ITmfStateInterval interval = doSingularQuery(t, i);
239 currentStateInfo.set(i, interval);
240 }
241 }
242 }
243
244 @Override
245 public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
246 throws TimeRangeException, StateSystemDisposedException {
247 ITmfStateInterval ret = super.doSingularQuery(t, attributeQuark);
248 if (ret != null) {
249 return ret;
250 }
251
252 /*
253 * We couldn't find the interval in the history tree. It's possible that
254 * it is currently in the intervalQueue. Look for it there. Note that
f00251b5
AM
255 * BufferedBlockingQueue's iterator() is thread-safe (no need to lock
256 * the queue).
e62a23a9 257 */
4cdea8fc
MK
258 for (ITmfStateInterval interval : intervalQueue) {
259 if (interval.getAttribute() == attributeQuark && interval.intersects(t)) {
260 return interval;
e62a23a9
AM
261 }
262 }
263
264 /*
265 * If we missed it again, it's because it got inserted in the tree
266 * *while we were iterating* on the queue. One last pass in the tree
267 * should find it.
268 *
d740e018
MK
269 * This case is really rare, which is why we do a second pass at the end
270 * if needed, instead of systematically checking in the queue first
e62a23a9
AM
271 * (which is slow).
272 */
273 return super.doSingularQuery(t, attributeQuark);
274 }
275
a52fde77 276}
This page took 0.136611 seconds and 5 git commands to generate.