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