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