1 /*******************************************************************************
2 * Copyright (c) 2012 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.trace
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Collections
;
17 import java
.util
.List
;
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
.trace
.TmfExperimentContext
;
24 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
25 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfTimestamp
;
26 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
27 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfDataRequest
;
28 import org
.eclipse
.linuxtools
.tmf
.core
.request
.ITmfEventRequest
;
29 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfDataRequest
;
30 import org
.eclipse
.linuxtools
.tmf
.core
.request
.TmfEventRequest
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceUpdatedSignal
;
34 * A simple indexer that manages the trace index as an array of trace
35 * checkpoints. Checkpoints are stored at fixed intervals (event rank) in
36 * ascending timestamp order.
38 * The goal being to access a random trace event reasonably fast from the user's
39 * standpoint, picking the right interval value becomes a trade-off between speed
40 * and memory usage (a shorter inter-event interval is faster but requires more
43 * Locating a specific checkpoint is trivial for both rank (rank % interval) and
44 * timestamp (bsearch in the array).
47 * @author Francois Chouinard
52 public class TmfCheckpointIndexer
<T
extends ITmfTrace
<ITmfEvent
>> implements ITmfTraceIndexer
<T
> {
54 // ------------------------------------------------------------------------
56 // ------------------------------------------------------------------------
58 // The event trace to index
59 protected final ITmfTrace
<ITmfEvent
> fTrace
;
61 // The interval between checkpoints
62 private final int fCheckpointInterval
;
64 // The event trace to index
65 private boolean fIsIndexing
;
68 * The trace index. It is composed of checkpoints taken at intervals of
69 * fCheckpointInterval events.
71 protected final List
<ITmfCheckpoint
> fTraceIndex
;
74 * The indexing request
76 private ITmfEventRequest
<ITmfEvent
> fIndexingRequest
= null;
78 // ------------------------------------------------------------------------
80 // ------------------------------------------------------------------------
83 * Basic constructor that uses the default trace block size as checkpoints
86 * @param trace the trace to index
88 public TmfCheckpointIndexer(final ITmfTrace
<ITmfEvent
> trace
) {
89 this(trace
, TmfTrace
.DEFAULT_BLOCK_SIZE
);
95 * @param trace the trace to index
96 * @param interval the checkpoints interval
98 public TmfCheckpointIndexer(final ITmfTrace
<ITmfEvent
> trace
, final int interval
) {
100 fCheckpointInterval
= interval
;
101 fTraceIndex
= new ArrayList
<ITmfCheckpoint
>();
106 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#dispose()
109 public void dispose() {
110 if ((fIndexingRequest
!= null) && !fIndexingRequest
.isCompleted()) {
111 fIndexingRequest
.cancel();
116 // ------------------------------------------------------------------------
117 // ITmfTraceIndexer - isIndexing
118 // ------------------------------------------------------------------------
121 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#isIndexing()
124 public boolean isIndexing() {
128 // ------------------------------------------------------------------------
129 // ITmfTraceIndexer - buildIndex
130 // ------------------------------------------------------------------------
134 * The index is a list of contexts that point to events at regular interval
135 * (rank-wise) in the trace. After it is built, the index can be used to
136 * quickly access any event by rank or timestamp (using seekIndex()).
138 * The index is built simply by reading the trace
140 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#buildIndex(long, org.eclipse.linuxtools.tmf.core.event.TmfTimeRange, boolean)
143 public void buildIndex(final long offset
, final TmfTimeRange range
, final boolean waitForCompletion
) {
145 // Don't do anything if we are already indexing
146 synchronized (fTraceIndex
) {
153 // The monitoring job
154 final Job job
= new Job("Indexing " + fTrace
.getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
156 protected IStatus
run(final IProgressMonitor monitor
) {
157 while (!monitor
.isCanceled()) {
160 } catch (final InterruptedException e
) {
161 return Status
.OK_STATUS
;
165 return Status
.OK_STATUS
;
170 // Build a background request for all the trace data. The index is
171 // updated as we go by readNextEvent().
172 fIndexingRequest
= new TmfEventRequest
<ITmfEvent
>(ITmfEvent
.class,
173 range
, offset
, TmfDataRequest
.ALL_DATA
, fCheckpointInterval
, ITmfDataRequest
.ExecutionType
.BACKGROUND
)
175 private ITmfTimestamp startTime
= null;
176 private ITmfTimestamp lastTime
= null;
179 public void handleData(final ITmfEvent event
) {
180 super.handleData(event
);
182 final ITmfTimestamp timestamp
= event
.getTimestamp();
183 if (startTime
== null) {
184 startTime
= timestamp
.clone();
186 lastTime
= timestamp
.clone();
188 // Update the trace status at regular intervals
189 if ((getNbRead() % fCheckpointInterval
) == 0) {
196 public void handleSuccess() {
201 public void handleCompleted() {
203 super.handleCompleted();
207 private void updateTraceStatus() {
208 if (getNbRead() != 0) {
209 signalNewTimeRange(startTime
, lastTime
);
214 // Submit the request and wait for completion if required
215 fTrace
.sendRequest(fIndexingRequest
);
216 if (waitForCompletion
) {
218 fIndexingRequest
.waitForCompletion();
219 } catch (final InterruptedException e
) {
225 * Notify the interested parties that the trace time range has changed
227 * @param startTime the new start time
228 * @param endTime the new end time
230 private void signalNewTimeRange(final ITmfTimestamp startTime
, final ITmfTimestamp endTime
) {
231 fTrace
.broadcast(new TmfTraceUpdatedSignal(fTrace
, fTrace
, new TmfTimeRange(startTime
, endTime
)));
234 // ------------------------------------------------------------------------
235 // ITmfTraceIndexer - updateIndex
236 // ------------------------------------------------------------------------
239 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#updateIndex(org.eclipse.linuxtools.tmf.core.trace.ITmfContext, org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
242 public synchronized void updateIndex(final ITmfContext context
, final ITmfTimestamp timestamp
) {
243 final long rank
= context
.getRank();
244 if ((rank
% fCheckpointInterval
) == 0) {
245 // Determine the table position
246 final long position
= rank
/ fCheckpointInterval
;
247 // Add new entry at proper location (if empty)
248 if (fTraceIndex
.size() == position
) {
249 fTraceIndex
.add(new TmfCheckpoint(timestamp
.clone(), shrinkContext(context
)));
254 // ------------------------------------------------------------------------
255 // ITmfTraceIndexer - seekIndex
256 // ------------------------------------------------------------------------
259 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#seekIndex(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
262 public synchronized ITmfContext
seekIndex(final ITmfTimestamp timestamp
) {
264 // A null timestamp indicates to seek the first event
265 if (timestamp
== null) {
266 return fTrace
.seekEvent(0);
269 // Find the checkpoint at or before the requested timestamp.
270 // In the very likely event that the timestamp is not at a checkpoint
271 // boundary, bsearch will return index = (- (insertion point + 1)).
272 // It is then trivial to compute the index of the previous checkpoint.
273 int index
= Collections
.binarySearch(fTraceIndex
, new TmfCheckpoint(timestamp
, null));
275 index
= Math
.max(0, -(index
+ 2));
278 // Position the trace at the checkpoint
279 return restoreCheckpoint(index
);
283 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#seekIndex(long)
286 public ITmfContext
seekIndex(final long rank
) {
288 // A rank < 0 indicates to seek the first event
290 return fTrace
.seekEvent(0);
293 // Find the checkpoint at or before the requested rank.
294 final int index
= (int) rank
/ fCheckpointInterval
;
296 // Position the trace at the checkpoint
297 return restoreCheckpoint(index
);
301 * Position the trace at the given checkpoint
303 * @param checkpoint the checkpoint index
304 * @return the corresponding context
306 private ITmfContext
restoreCheckpoint(final int checkpoint
) {
307 ITmfLocation
<?
> location
= null;
309 synchronized (fTraceIndex
) {
310 if (!fTraceIndex
.isEmpty()) {
312 if (index
>= fTraceIndex
.size()) {
313 index
= fTraceIndex
.size() - 1;
315 return restoreContext(fTraceIndex
.get(index
).getContext());
318 final ITmfContext context
= fTrace
.seekEvent(location
);
319 context
.setRank((long) index
* fCheckpointInterval
);
323 // ------------------------------------------------------------------------
325 // ------------------------------------------------------------------------
328 * @return the trace index
330 protected List
<ITmfCheckpoint
> getTraceIndex() {
334 // ------------------------------------------------------------------------
335 // Context conversion functions
336 // ------------------------------------------------------------------------
338 private ITmfContext
shrinkContext(ITmfContext context
) {
339 if (context
instanceof TmfExperimentContext
) {
340 return shrinkExpContext(context
);
342 TmfContext ctx
= new TmfContext(context
.getLocation().clone(), context
.getRank());
346 private ITmfContext
shrinkExpContext(ITmfContext context
) {
347 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
348 int size
= expContext
.getContexts().length
;
349 ITmfContext
[] trcCtxts
= new TmfContext
[size
];
350 for (int i
= 0; i
< size
; i
++) {
351 ITmfContext ctx
= expContext
.getContexts()[i
];
352 trcCtxts
[i
] = (ctx
!= null) ?
new TmfContext(ctx
.getLocation().clone(), ctx
.getRank()) : null;
354 TmfExperimentContext expCtx
= new TmfExperimentContext(trcCtxts
);
355 expCtx
.setLocation(context
.getLocation().clone());
356 expCtx
.setRank(context
.getRank());
357 ITmfEvent
[] trcEvts
= expCtx
.getEvents();
358 for (int i
= 0; i
< size
; i
++) {
359 ITmfEvent event
= expContext
.getEvents()[i
];
360 trcEvts
[i
] = (event
!= null) ? event
.clone() : null;
365 private ITmfContext
restoreContext(ITmfContext context
) {
366 if (context
instanceof TmfExperimentContext
) {
367 return restoreExpContext(context
);
369 ITmfContext ctx
= fTrace
.seekEvent(context
.getLocation());
370 ctx
.setRank(context
.getRank());
374 private ITmfContext
restoreExpContext(ITmfContext context
) {
375 TmfExperimentContext expContext
= (TmfExperimentContext
) context
;
376 int size
= expContext
.getContexts().length
;
377 ITmfContext
[] trcCtxts
= new ITmfContext
[size
];
378 for (int i
= 0; i
< size
; i
++) {
379 ITmfTrace
<?
> trace
= ((TmfExperiment
<?
>) fTrace
).getTraces()[i
];
380 ITmfContext ctx
= expContext
.getContexts()[i
];
381 trcCtxts
[i
] = trace
.seekEvent(ctx
.getLocation().clone());
382 trcCtxts
[i
].setRank(ctx
.getRank());
384 TmfExperimentContext ctx
= new TmfExperimentContext(trcCtxts
);
385 ctx
.setLocation(context
.getLocation().clone());
386 ctx
.setRank(context
.getRank());
387 ITmfEvent
[] trcEvts
= expContext
.getEvents();
388 for (int i
= 0; i
< size
; i
++) {
389 ITmfEvent event
= trcEvts
[i
];
390 ctx
.getEvents()[i
] = (event
!= null) ? event
.clone() : null;