tmf: Clean up tmf.core.trace package
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / indexer / checkpoint / TmfCheckpointIndexer.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint;
14
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.core.runtime.Status;
22 import org.eclipse.core.runtime.jobs.Job;
23 import org.eclipse.linuxtools.internal.tmf.core.Messages;
24 import org.eclipse.linuxtools.tmf.core.component.TmfDataProvider;
25 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
26 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
27 import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest;
28 import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
29 import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
30 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
31 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
32 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
33 import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
34 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
35 import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
36 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
37
38 /**
39 * A simple indexer that manages the trace index as an array of trace
40 * checkpoints. Checkpoints are stored at fixed intervals (event rank) in
41 * ascending timestamp order.
42 * <p>
43 * The goal being to access a random trace event reasonably fast from the user's
44 * standpoint, picking the right interval value becomes a trade-off between speed
45 * and memory usage (a shorter inter-event interval is faster but requires more
46 * checkpoints).
47 * <p>
48 * Locating a specific checkpoint is trivial for both rank (rank % interval) and
49 * timestamp (bsearch in the array).
50 * *
51 * @see ITmfTrace
52 * @see ITmfEvent
53 *
54 * @author Francois Chouinard
55 * @since 3.0
56 */
57 public class TmfCheckpointIndexer implements ITmfTraceIndexer {
58
59 // ------------------------------------------------------------------------
60 // Attributes
61 // ------------------------------------------------------------------------
62
63 /** The event trace to index */
64 protected final ITmfTrace fTrace;
65
66 /** The interval between checkpoints */
67 private final int fCheckpointInterval;
68
69 /** The event trace to index */
70 private boolean fIsIndexing;
71
72 /**
73 * The trace index. It is composed of checkpoints taken at intervals of
74 * fCheckpointInterval events.
75 */
76 protected final List<ITmfCheckpoint> fTraceIndex;
77
78 /**
79 * The indexing request
80 */
81 private ITmfEventRequest fIndexingRequest = null;
82
83 // ------------------------------------------------------------------------
84 // Construction
85 // ------------------------------------------------------------------------
86
87 /**
88 * Basic constructor that uses the default trace block size as checkpoints
89 * intervals
90 *
91 * @param trace the trace to index
92 */
93 public TmfCheckpointIndexer(final ITmfTrace trace) {
94 this(trace, TmfDataProvider.DEFAULT_BLOCK_SIZE);
95 }
96
97 /**
98 * Full trace indexer
99 *
100 * @param trace the trace to index
101 * @param interval the checkpoints interval
102 */
103 public TmfCheckpointIndexer(final ITmfTrace trace, final int interval) {
104 fTrace = trace;
105 fCheckpointInterval = interval;
106 fTraceIndex = new ArrayList<ITmfCheckpoint>();
107 fIsIndexing = false;
108 }
109
110 @Override
111 public void dispose() {
112 if ((fIndexingRequest != null) && !fIndexingRequest.isCompleted()) {
113 fIndexingRequest.cancel();
114 fTraceIndex.clear();
115 }
116 }
117
118 // ------------------------------------------------------------------------
119 // ITmfTraceIndexer - isIndexing
120 // ------------------------------------------------------------------------
121
122 @Override
123 public boolean isIndexing() {
124 return fIsIndexing;
125 }
126
127 // ------------------------------------------------------------------------
128 // ITmfTraceIndexer - buildIndex
129 // ------------------------------------------------------------------------
130
131 /**
132 * @since 2.0
133 */
134 @Override
135 public void buildIndex(final long offset, final TmfTimeRange range, final boolean waitForCompletion) {
136
137 // Don't do anything if we are already indexing
138 synchronized (fTraceIndex) {
139 if (fIsIndexing) {
140 return;
141 }
142 fIsIndexing = true;
143 }
144
145 // The monitoring job
146 final Job job = new Job("Indexing " + fTrace.getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
147 @Override
148 protected IStatus run(final IProgressMonitor monitor) {
149 monitor.beginTask("", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
150 while (!monitor.isCanceled()) {
151 try {
152 long prevNbEvents = fTrace.getNbEvents();
153 Thread.sleep(250);
154 long nbEvents = fTrace.getNbEvents();
155 setName(Messages.TmfCheckpointIndexer_Indexing + ' ' + fTrace.getName() + " (" + nbEvents + ")"); //$NON-NLS-1$ //$NON-NLS-2$
156 // setName doesn't refresh the UI, setTaskName does
157 long rate = (nbEvents - prevNbEvents) * 4;
158 monitor.setTaskName(rate + " " + Messages.TmfCheckpointIndexer_EventsPerSecond); //$NON-NLS-1$
159 } catch (final InterruptedException e) {
160 return Status.OK_STATUS;
161 }
162 }
163 monitor.done();
164 return Status.OK_STATUS;
165 }
166 };
167 job.schedule();
168
169 // Build a background request for all the trace data. The index is
170 // updated as we go by readNextEvent().
171 fIndexingRequest = new TmfEventRequest(ITmfEvent.class,
172 range, offset, TmfDataRequest.ALL_DATA,
173 ITmfDataRequest.ExecutionType.BACKGROUND) {
174 @Override
175 public void handleData(final ITmfEvent event) {
176 super.handleData(event);
177 if (event != null) {
178 // Update the trace status at regular intervals
179 if ((getNbRead() % fCheckpointInterval) == 0) {
180 updateTraceStatus();
181 }
182 }
183 }
184
185 @Override
186 public void handleSuccess() {
187 updateTraceStatus();
188 }
189
190 @Override
191 public void handleCompleted() {
192 job.cancel();
193 super.handleCompleted();
194 fIsIndexing = false;
195 }
196
197 private void updateTraceStatus() {
198 if (fTrace.getNbEvents() > 0) {
199 signalNewTimeRange(fTrace.getStartTime(), fTrace.getEndTime());
200 }
201 }
202 };
203
204 // Submit the request and wait for completion if required
205 fTrace.sendRequest(fIndexingRequest);
206 if (waitForCompletion) {
207 try {
208 fIndexingRequest.waitForCompletion();
209 } catch (final InterruptedException e) {
210 }
211 }
212 }
213
214 /**
215 * Notify the interested parties that the trace time range has changed
216 *
217 * @param startTime the new start time
218 * @param endTime the new end time
219 */
220 private void signalNewTimeRange(final ITmfTimestamp startTime, final ITmfTimestamp endTime) {
221 fTrace.broadcast(new TmfTraceUpdatedSignal(fTrace, fTrace, new TmfTimeRange(startTime, endTime)));
222 }
223
224 // ------------------------------------------------------------------------
225 // ITmfTraceIndexer - updateIndex
226 // ------------------------------------------------------------------------
227
228 /**
229 * @since 2.0
230 */
231 @Override
232 public synchronized void updateIndex(final ITmfContext context, final ITmfTimestamp timestamp) {
233 if ((context.getRank() % fCheckpointInterval) == 0) {
234 // Determine the table position
235 final long position = context.getRank() / fCheckpointInterval;
236 // Add new entry at proper location (if empty)
237 if (fTraceIndex.size() == position) {
238 fTraceIndex.add(new TmfCheckpoint(timestamp, context.getLocation()));
239 }
240 }
241 }
242
243 // ------------------------------------------------------------------------
244 // ITmfTraceIndexer - seekIndex
245 // ------------------------------------------------------------------------
246
247 /**
248 * @since 2.0
249 */
250 @Override
251 public synchronized ITmfContext seekIndex(final ITmfTimestamp timestamp) {
252
253 // A null timestamp indicates to seek the first event
254 if (timestamp == null) {
255 return fTrace.seekEvent(0);
256 }
257
258 // Find the checkpoint at or before the requested timestamp.
259 // In the very likely event that the timestamp is not at a checkpoint
260 // boundary, bsearch will return index = (- (insertion point + 1)).
261 // It is then trivial to compute the index of the previous checkpoint.
262 int index = Collections.binarySearch(fTraceIndex, new TmfCheckpoint(timestamp, null));
263 if (index < 0) {
264 index = Math.max(0, -(index + 2));
265 } else {
266 // If timestamp was in the list, use previous index to be able to find the
267 // first event with the same timestamp before the checkpoint
268 index = Math.max(0, index - 1);
269 }
270
271 // Position the trace at the checkpoint
272 return restoreCheckpoint(index);
273 }
274
275 @Override
276 public ITmfContext seekIndex(final long rank) {
277
278 // A rank < 0 indicates to seek the first event
279 if (rank < 0) {
280 return fTrace.seekEvent(0);
281 }
282
283 // Find the checkpoint at or before the requested rank.
284 final int index = (int) rank / fCheckpointInterval;
285
286 // Position the trace at the checkpoint
287 return restoreCheckpoint(index);
288 }
289
290 /**
291 * Position the trace at the given checkpoint
292 *
293 * @param checkpoint the checkpoint index
294 * @return the corresponding context
295 */
296 private ITmfContext restoreCheckpoint(final int checkpoint) {
297 ITmfLocation location = null;
298 int index = 0;
299 synchronized (fTraceIndex) {
300 if (!fTraceIndex.isEmpty()) {
301 index = checkpoint;
302 if (index >= fTraceIndex.size()) {
303 index = fTraceIndex.size() - 1;
304 }
305 location = fTraceIndex.get(index).getLocation();
306 }
307 }
308 final ITmfContext context = fTrace.seekEvent(location);
309 context.setRank((long) index * fCheckpointInterval);
310 return context;
311 }
312
313 // ------------------------------------------------------------------------
314 // Getters
315 // ------------------------------------------------------------------------
316
317 /**
318 * @return the trace index
319 */
320 protected List<ITmfCheckpoint> getTraceIndex() {
321 return fTraceIndex;
322 }
323
324 }
This page took 0.037119 seconds and 5 git commands to generate.