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