tmf: Add a state system explorer view
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / partial / PartialHistoryBackend.java
CommitLineData
1b9d3765
AM
1/*******************************************************************************
2 * Copyright (c) 2013 Ericsson
3 * All rights reserved. This program and the accompanying materials are
4 * made available under the terms of the Eclipse Public License v1.0 which
5 * accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Alexandre Montplaisir - Initial API and implementation
10 *******************************************************************************/
11
12package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.partial;
13
14import java.io.File;
15import java.io.FileInputStream;
16import java.io.PrintWriter;
17import java.util.List;
18import java.util.Map;
19import java.util.TreeMap;
20import java.util.concurrent.CountDownLatch;
21
22import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend;
23import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
24import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
25import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
26import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
27import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
28import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
29import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
30import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
31import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
32import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
33import org.eclipse.linuxtools.tmf.core.statesystem.AbstractStateChangeInput;
34import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput;
35import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
36import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
37import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
38import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
39
40/**
41 * Partial state history back-end.
42 *
43 * This is a shim inserted between the real state system and a "real" history
44 * back-end. It will keep checkpoints, every n trace events (where n is called
45 * the granularity) and will only forward to the real state history the state
46 * intervals that crosses at least one checkpoint. Every other interval will
47 * be discarded.
48 *
49 * This would mean that it can only answer queries exactly at the checkpoints.
50 * For any other timestamps (ie, most of the time), it will load the closest
51 * earlier checkpoint, and will re-feed the state-change-input with events from
52 * the trace, to restore the real state at the time that was requested.
53 *
54 * @author Alexandre Montplaisir
55 */
56public class PartialHistoryBackend implements IStateHistoryBackend {
57
58 /**
59 * A partial history needs the state input plugin to re-generate state
60 * between checkpoints.
61 */
62 private final IStateChangeInput partialInput;
63
64 /**
65 * Fake state system that is used for partially rebuilding the states (when
66 * going from a checkpoint to a target query timestamp).
67 */
68 private final PartialStateSystem partialSS;
69
70 /** Reference to the "real" state history that is used for storage */
71 private final IStateHistoryBackend innerHistory;
72
73 /** Checkpoints map, <Timestamp, Rank in the trace> */
74 private final TreeMap<Long, Long> checkpoints =
75 new TreeMap<Long, Long>();
76
77 /** Latch tracking if the initial checkpoint registration is done */
78 private final CountDownLatch checkpointsReady = new CountDownLatch(1);
79
80 private final long granularity;
81
82 private long latestTime;
83
84 /**
85 * Constructor
86 *
87 * @param partialInput
88 * The state change input object that was used to build the
89 * upstream state system. This partial history will make its own
90 * copy (since they have different targets).
91 * @param pss
92 * The partial history's inner state system. It should already be
93 * assigned to partialInput.
94 * @param realBackend
95 * The real state history back-end to use. It's supposed to be
96 * modular, so it should be able to be of any type.
97 * @param granularity
98 * Configuration parameter indicating how many trace events there
99 * should be between each checkpoint
100 */
101 public PartialHistoryBackend(IStateChangeInput partialInput, PartialStateSystem pss,
102 IStateHistoryBackend realBackend, long granularity) {
103 if (granularity <= 0 || partialInput == null || pss == null) {
104 throw new IllegalArgumentException();
105 }
106 if (partialInput.getAssignedStateSystem() != pss) {
107 throw new RuntimeException();
108 }
109
110 final long startTime = realBackend.getStartTime();
111
112 this.partialInput = partialInput;
113 this.partialSS = pss;
114
115 this.innerHistory = realBackend;
116 this.granularity = granularity;
117
118 latestTime = startTime;
119
120 registerCheckpoints();
121 }
122
123 private void registerCheckpoints() {
124 ITmfEventRequest request = new CheckpointsRequest(partialInput, checkpoints);
125 partialInput.getTrace().sendRequest(request);
126 /* The request will countDown the checkpoints latch once it's finished */
127 }
128
129 @Override
130 public long getStartTime() {
131 return innerHistory.getStartTime();
132 }
133
134 @Override
135 public long getEndTime() {
136 return latestTime;
137 }
138
139 @Override
140 public void insertPastState(long stateStartTime, long stateEndTime,
141 int quark, ITmfStateValue value) throws TimeRangeException {
142 waitForCheckpoints();
143
144 /* Update the latest time */
145 if (stateEndTime > latestTime) {
146 latestTime = stateEndTime;
147 }
148
149 /*
150 * Check if the interval intersects the previous checkpoint. If so,
151 * insert it in the real history back-end.
152 *
153 * FIXME since intervals are inserted in order of rank, we could avoid
154 * doing a map lookup every time here (just compare with the known
155 * previous one).
156 */
157 if (stateStartTime <= checkpoints.floorKey(stateEndTime)) {
158 innerHistory.insertPastState(stateStartTime, stateEndTime, quark, value);
159 }
160 }
161
162 @Override
163 public void finishedBuilding(long endTime) throws TimeRangeException {
164 innerHistory.finishedBuilding(endTime);
165 }
166
167 @Override
168 public FileInputStream supplyAttributeTreeReader() {
169 return innerHistory.supplyAttributeTreeReader();
170 }
171
172 @Override
173 public File supplyAttributeTreeWriterFile() {
174 return innerHistory.supplyAttributeTreeWriterFile();
175 }
176
177 @Override
178 public long supplyAttributeTreeWriterFilePosition() {
179 return innerHistory.supplyAttributeTreeWriterFilePosition();
180 }
181
182 @Override
183 public void removeFiles() {
184 innerHistory.removeFiles();
185 }
186
187 @Override
188 public void dispose() {
189 innerHistory.dispose();
190 }
191
192 @Override
193 public void doQuery(List<ITmfStateInterval> currentStateInfo, long t)
194 throws TimeRangeException, StateSystemDisposedException {
195 /* Wait for required steps to be done */
196 waitForCheckpoints();
197 partialSS.getUpstreamSS().waitUntilBuilt();
198
199 if (!checkValidTime(t)) {
200 throw new TimeRangeException();
201 }
202
203 /* Reload the previous checkpoint */
204 long checkpointTime = checkpoints.floorKey(t);
205 innerHistory.doQuery(currentStateInfo, checkpointTime);
206
207 /*
208 * Set the initial contents of the partial state system (which is the
209 * contents of the query at the checkpoint).
210 */
211 partialSS.takeQueryLock();
212 partialSS.replaceOngoingState(currentStateInfo);
213
214 /* Send an event request to update the state system to the target time. */
215 TmfTimeRange range = new TmfTimeRange(
216 new TmfTimestamp(checkpointTime, -9), new TmfTimestamp(t, -9));
217 ITmfEventRequest request = new PartialStateSystemRequest(partialInput, range);
218 partialInput.getTrace().sendRequest(request);
219
220 try {
221 request.waitForCompletion();
222 } catch (InterruptedException e) {
223 e.printStackTrace();
224 }
225
226 /*
227 * Now the partial state system should have the ongoing time we are
228 * looking for. However, the method expects a List of *state intervals*,
229 * not state values, so we'll create intervals with a dummy end time.
230 */
231 try {
232 for (int i = 0; i < currentStateInfo.size(); i++) {
233 long start = 0;
234 ITmfStateValue val = null;
235 start = partialSS.getOngoingStartTime(i);
236 val = partialSS.queryOngoingState(i);
237
238 ITmfStateInterval interval = new TmfStateInterval(start, t, i, val);
239 currentStateInfo.set(i, interval);
240 }
241 } catch (AttributeNotFoundException e) {
242 /* Should not happen, we iterate over existing values. */
243 e.printStackTrace();
244 }
245
246 partialSS.releaseQueryLock();
247 }
248
249 /**
250 * Single queries are not supported in partial histories. To get the same
251 * result you can do a full query, then call fullState.get(attribute).
252 */
253 @Override
254 public ITmfStateInterval doSingularQuery(long t, int attributeQuark) {
255 throw new UnsupportedOperationException();
256 }
257
258 @Override
259 public boolean checkValidTime(long t) {
260 return (t >= getStartTime() && t <= getEndTime());
261 }
262
263 @Override
264 public void debugPrint(PrintWriter writer) {
265 // TODO Auto-generated method stub
266 }
267
268 private void waitForCheckpoints() {
269 try {
270 checkpointsReady.await();
271 } catch (InterruptedException e) {
272 e.printStackTrace();
273 }
274 }
275
276 // ------------------------------------------------------------------------
277 // Event requests types
278 // ------------------------------------------------------------------------
279
280 private class CheckpointsRequest extends TmfEventRequest {
281
282 /** The amount of events queried at a time through the requests */
283 private final static int chunkSize = 50000;
284
285 private final ITmfTrace trace;
286 private final Map<Long, Long> checkpts;
287 private long eventCount;
288 private long lastCheckpointAt;
289
290 public CheckpointsRequest(IStateChangeInput input, Map<Long, Long> checkpoints) {
291 super(input.getExpectedEventType(),
292 TmfTimeRange.ETERNITY,
293 TmfDataRequest.ALL_DATA,
294 chunkSize,
295 ITmfDataRequest.ExecutionType.BACKGROUND);
296 checkpoints.clear();
297 this.trace = input.getTrace();
298 this.checkpts = checkpoints;
299 eventCount = lastCheckpointAt = 0;
300
301 /* Insert a checkpoint at the start of the trace */
302 checkpoints.put(input.getStartTime(), 0L);
303 }
304
305 @Override
306 public void handleData(final ITmfEvent event) {
307 super.handleData(event);
308 if (event != null && event.getTrace() == trace) {
309 eventCount++;
310
311 /* Check if we need to register a new checkpoint */
312 if (eventCount >= lastCheckpointAt + granularity) {
313 checkpts.put(event.getTimestamp().getValue(), eventCount);
314 lastCheckpointAt = eventCount;
315 }
316 }
317 }
318
319 @Override
320 public void handleCompleted() {
321 super.handleCompleted();
322 checkpointsReady.countDown();
323 }
324 }
325
326 private class PartialStateSystemRequest extends TmfEventRequest {
327
328 private final static int chunkSize = 50000;
329 private final IStateChangeInput sci;
330 private final ITmfTrace trace;
331
332 PartialStateSystemRequest(IStateChangeInput sci, TmfTimeRange range) {
333 super(sci.getExpectedEventType(),
334 range,
335 TmfDataRequest.ALL_DATA,
336 chunkSize,
337 ITmfDataRequest.ExecutionType.BACKGROUND);
338 this.sci = sci;
339 this.trace = sci.getTrace();
340 }
341
342 @Override
343 public void handleData(final ITmfEvent event) {
344 super.handleData(event);
345 if (event != null && event.getTrace() == trace) {
346 sci.processEvent(event);
347 }
348 }
349
350 @Override
351 public void handleCompleted() {
352 /*
353 * If we're using a threaded state provider, we need to make sure
354 * all events have been handled by the state system before doing
355 * queries on it.
356 */
357 if (partialInput instanceof AbstractStateChangeInput) {
358 ((AbstractStateChangeInput) partialInput).waitForEmptyQueue();
359 }
360 super.handleCompleted();
361 }
362
363
364 }
365}
This page took 0.037752 seconds and 5 git commands to generate.