TMF: Change visibility of TmfEventMatching methods
[deliverable/tracecompass.git] / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / 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
e894a508 15package org.eclipse.tracecompass.statesystem.core.backend.historytree;
a52fde77
AM
16
17import java.io.File;
18import java.io.IOException;
e62a23a9 19import java.util.List;
a52fde77
AM
20import java.util.concurrent.ArrayBlockingQueue;
21import java.util.concurrent.BlockingQueue;
22
e62a23a9 23import org.eclipse.jdt.annotation.NonNull;
e894a508
AM
24import org.eclipse.tracecompass.internal.statesystem.core.Activator;
25import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTInterval;
e62a23a9 26import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
e894a508 27import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
e62a23a9 28import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
e894a508
AM
29import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
30import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
a52fde77
AM
31
32/**
33 * Variant of the HistoryTreeBackend which runs all the interval-insertion logic
34 * in a separate thread.
1a4205d9 35 *
bcec0116 36 * @author Alexandre Montplaisir
a52fde77 37 */
ab604305
AM
38public final class ThreadedHistoryTreeBackend extends HistoryTreeBackend
39 implements Runnable {
a52fde77 40
e62a23a9
AM
41 private final @NonNull BlockingQueue<HTInterval> intervalQueue;
42 private final @NonNull Thread shtThread;
a52fde77
AM
43
44 /**
45 * New state history constructor
1a4205d9 46 *
a52fde77
AM
47 * Note that it usually doesn't make sense to use a Threaded HT if you're
48 * opening an existing state-file, but you know what you're doing...
1a4205d9 49 *
b2f62cb5
AM
50 * @param ssid
51 * The state system's id
a52fde77
AM
52 * @param newStateFile
53 * The name of the history file that will be created. Should end
54 * in ".ht"
55 * @param blockSize
56 * The size of the blocks in the file
57 * @param maxChildren
58 * The maximum number of children allowed for each core node
59 * @param startTime
60 * The earliest timestamp stored in the history
a96cc6be
AM
61 * @param providerVersion
62 * Version of of the state provider. We will only try to reopen
63 * existing files if this version matches the one in the
64 * framework.
a52fde77
AM
65 * @param queueSize
66 * The size of the interval insertion queue. 2000 - 10000 usually
67 * works well
68 * @throws IOException
69 * If there was a problem opening the history file for writing
dbc7991d 70 * @since 1.0
a52fde77 71 */
b2f62cb5 72 public ThreadedHistoryTreeBackend(@NonNull String ssid, File newStateFile, int blockSize,
a96cc6be 73 int maxChildren, long startTime, int providerVersion, int queueSize)
d740e018 74 throws IOException {
b2f62cb5 75 super(ssid, newStateFile, blockSize, maxChildren, providerVersion, startTime);
a52fde77 76
a4524c1b 77 intervalQueue = new ArrayBlockingQueue<>(queueSize);
a52fde77
AM
78 shtThread = new Thread(this, "History Tree Thread"); //$NON-NLS-1$
79 shtThread.start();
80 }
81
82 /**
83 * New State History constructor. This version provides default values for
84 * blockSize and maxChildren.
1a4205d9 85 *
b2f62cb5
AM
86 * @param ssid
87 * The state system's id
a52fde77
AM
88 * @param newStateFile
89 * The name of the history file that will be created. Should end
90 * in ".ht"
91 * @param startTime
92 * The earliest timestamp stored in the history
a96cc6be
AM
93 * @param providerVersion
94 * Version of of the state provider. We will only try to reopen
95 * existing files if this version matches the one in the
96 * framework.
a52fde77
AM
97 * @param queueSize
98 * The size of the interval insertion queue. 2000 - 10000 usually
99 * works well
100 * @throws IOException
101 * If there was a problem opening the history file for writing
dbc7991d 102 * @since 1.0
a52fde77 103 */
b2f62cb5 104 public ThreadedHistoryTreeBackend(@NonNull String ssid, File newStateFile, long startTime,
a96cc6be 105 int providerVersion, int queueSize) throws IOException {
b2f62cb5 106 super(ssid, newStateFile, providerVersion, startTime);
a52fde77 107
a4524c1b 108 intervalQueue = new ArrayBlockingQueue<>(queueSize);
a52fde77
AM
109 shtThread = new Thread(this, "History Tree Thread"); //$NON-NLS-1$
110 shtThread.start();
111 }
112
113 /*
114 * The Threaded version does not specify an "existing file" constructor,
115 * since the history is already built (and we only use the other thread
116 * during building). Just use a plain HistoryTreeProvider in this case.
1a4205d9 117 *
a52fde77
AM
118 * TODO but what about streaming??
119 */
120
121 @Override
122 public void insertPastState(long stateStartTime, long stateEndTime,
123 int quark, ITmfStateValue value) throws TimeRangeException {
124 /*
125 * Here, instead of directly inserting the elements in the History Tree
126 * underneath, we'll put them in the Queue. They will then be taken and
127 * processed by the other thread executing the run() method.
128 */
129 HTInterval interval = new HTInterval(stateStartTime, stateEndTime,
130 quark, (TmfStateValue) value);
131 try {
132 intervalQueue.put(interval);
133 } catch (InterruptedException e) {
bcec0116 134 Activator.getDefault().logError("State system interrupted", e); //$NON-NLS-1$
a52fde77
AM
135 }
136 }
137
138 @Override
b33c7369 139 public void finishedBuilding(long endTime) {
a52fde77
AM
140 /*
141 * We need to commit everything in the History Tree and stop the
142 * standalone thread before returning to the StateHistorySystem. (SHS
143 * will then write the Attribute Tree to the file, that must not happen
144 * at the same time we are writing the last nodes!)
145 */
146
1a4205d9 147 stopRunningThread(endTime);
d740e018 148 setFinishedBuilding(true);
1a4205d9
AM
149 return;
150 }
151
152 @Override
153 public void dispose() {
d740e018 154 if (!isFinishedBuilding()) {
bcec0116 155 stopRunningThread(Long.MAX_VALUE);
1a4205d9 156 }
a52fde77 157 /*
1a4205d9
AM
158 * isFinishedBuilding remains false, so the superclass will ask the
159 * back-end to delete the file.
160 */
161 super.dispose();
162 }
163
164 private void stopRunningThread(long endTime) {
165 if (!shtThread.isAlive()) {
166 return;
167 }
168
169 /*
d740e018
MK
170 * Send a "poison pill" in the queue, then wait for the HT to finish its
171 * closeTree()
a52fde77
AM
172 */
173 try {
1a4205d9 174 HTInterval pill = new HTInterval(-1, endTime, -1, TmfStateValue.nullValue());
b33c7369 175 intervalQueue.put(pill);
a52fde77 176 shtThread.join();
b33c7369 177 } catch (TimeRangeException e) {
bcec0116 178 Activator.getDefault().logError("Error closing state system", e); //$NON-NLS-1$
a52fde77 179 } catch (InterruptedException e) {
bcec0116 180 Activator.getDefault().logError("State system interrupted", e); //$NON-NLS-1$
a52fde77 181 }
a52fde77
AM
182 }
183
184 @Override
185 public void run() {
a52fde77
AM
186 HTInterval currentInterval;
187 try {
188 currentInterval = intervalQueue.take();
189 while (currentInterval.getStartTime() != -1) {
190 /* Send the interval to the History Tree */
e62a23a9 191 getSHT().insertInterval(currentInterval);
a52fde77
AM
192 currentInterval = intervalQueue.take();
193 }
e62a23a9
AM
194 if (currentInterval.getAttribute() != -1) {
195 /* Make sure this is the "poison pill" we are waiting for */
196 throw new IllegalStateException();
197 }
a52fde77 198 /*
6a1074ce
AM
199 * We've been told we're done, let's write down everything and quit.
200 * The end time of this "signal interval" is actually correct.
a52fde77 201 */
e62a23a9 202 getSHT().closeTree(currentInterval.getEndTime());
a52fde77
AM
203 return;
204 } catch (InterruptedException e) {
205 /* We've been interrupted abnormally */
bcec0116 206 Activator.getDefault().logError("State History Tree interrupted!", e); //$NON-NLS-1$
a52fde77
AM
207 } catch (TimeRangeException e) {
208 /* This also 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
255 * ArrayBlockingQueue's iterator() is thread-safe (no need to lock the
256 * queue).
257 */
258 for (ITmfStateInterval interval : intervalQueue) {
259 if (interval.getAttribute() == attributeQuark && interval.intersects(t)) {
260 return interval;
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.072188 seconds and 5 git commands to generate.