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;