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