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