~ubuntu-branches/ubuntu/trusty/eclipse-linuxtools/trusty

« back to all changes in this revision

Viewing changes to lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfCheckpointIndexer.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2012-06-29 12:07:30 UTC
  • Revision ID: package-import@ubuntu.com-20120629120730-bfri1xys1i71dpn6
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 * Copyright (c) 2012 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;
 
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.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;
 
32
 
 
33
/**
 
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.
 
37
 * <p>
 
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
 
41
 * checkpoints).
 
42
 * <p>
 
43
 * Locating a specific checkpoint is trivial for both rank (rank % interval) and
 
44
 * timestamp (bsearch in the array).
 
45
 * 
 
46
 * @version 1.0
 
47
 * @author Francois Chouinard
 
48
 *
 
49
 * @see ITmfTrace
 
50
 * @see ITmfEvent
 
51
 */
 
52
public class TmfCheckpointIndexer<T extends ITmfTrace<ITmfEvent>> implements ITmfTraceIndexer<T> {
 
53
 
 
54
    // ------------------------------------------------------------------------
 
55
    // Attributes
 
56
    // ------------------------------------------------------------------------
 
57
 
 
58
    // The event trace to index
 
59
    protected final ITmfTrace<ITmfEvent> fTrace;
 
60
 
 
61
    // The interval between checkpoints
 
62
    private final int fCheckpointInterval;
 
63
 
 
64
    // The event trace to index
 
65
    private boolean fIsIndexing;
 
66
 
 
67
    /**
 
68
     * The trace index. It is composed of checkpoints taken at intervals of
 
69
     * fCheckpointInterval events.
 
70
     */
 
71
    protected final List<ITmfCheckpoint> fTraceIndex;
 
72
 
 
73
    /**
 
74
     * The indexing request 
 
75
     */
 
76
    private ITmfEventRequest<ITmfEvent> fIndexingRequest = null;
 
77
    
 
78
    // ------------------------------------------------------------------------
 
79
    // Construction
 
80
    // ------------------------------------------------------------------------
 
81
 
 
82
    /**
 
83
     * Basic constructor that uses the default trace block size as checkpoints
 
84
     * intervals
 
85
     * 
 
86
     * @param trace the trace to index
 
87
     */
 
88
    public TmfCheckpointIndexer(final ITmfTrace<ITmfEvent> trace) {
 
89
        this(trace, TmfTrace.DEFAULT_BLOCK_SIZE);
 
90
    }
 
91
 
 
92
    /**
 
93
     * Full trace indexer
 
94
     * 
 
95
     * @param trace the trace to index
 
96
     * @param interval the checkpoints interval
 
97
     */
 
98
    public TmfCheckpointIndexer(final ITmfTrace<ITmfEvent> trace, final int interval) {
 
99
        fTrace = trace;
 
100
        fCheckpointInterval = interval;
 
101
        fTraceIndex = new ArrayList<ITmfCheckpoint>();
 
102
        fIsIndexing = false;
 
103
    }
 
104
 
 
105
    /* (non-Javadoc)
 
106
     * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#dispose()
 
107
     */
 
108
    @Override
 
109
    public void dispose() {
 
110
        if ((fIndexingRequest != null) && !fIndexingRequest.isCompleted()) {
 
111
            fIndexingRequest.cancel();
 
112
            fTraceIndex.clear();
 
113
        }
 
114
    }
 
115
 
 
116
    // ------------------------------------------------------------------------
 
117
    // ITmfTraceIndexer - isIndexing
 
118
    // ------------------------------------------------------------------------
 
119
 
 
120
    /* (non-Javadoc)
 
121
     * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#isIndexing()
 
122
     */
 
123
    @Override
 
124
    public boolean isIndexing() {
 
125
        return fIsIndexing;
 
126
    }
 
127
 
 
128
    // ------------------------------------------------------------------------
 
129
    // ITmfTraceIndexer - buildIndex
 
130
    // ------------------------------------------------------------------------
 
131
 
 
132
    /* (non-Javadoc)
 
133
     * 
 
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()).
 
137
     * 
 
138
     * The index is built simply by reading the trace
 
139
     *
 
140
     * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#buildIndex(long, org.eclipse.linuxtools.tmf.core.event.TmfTimeRange, boolean)
 
141
     */
 
142
    @Override
 
143
    public void buildIndex(final long offset, final TmfTimeRange range, final boolean waitForCompletion) {
 
144
 
 
145
        // Don't do anything if we are already indexing 
 
146
        synchronized (fTraceIndex) {
 
147
            if (fIsIndexing) {
 
148
                return;
 
149
            }
 
150
            fIsIndexing = true;
 
151
        }
 
152
 
 
153
        // The monitoring job
 
154
        final Job job = new Job("Indexing " + fTrace.getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
 
155
            @Override
 
156
            protected IStatus run(final IProgressMonitor monitor) {
 
157
                while (!monitor.isCanceled()) {
 
158
                    try {
 
159
                        Thread.sleep(100);
 
160
                    } catch (final InterruptedException e) {
 
161
                        return Status.OK_STATUS;
 
162
                    }
 
163
                }
 
164
                monitor.done();
 
165
                return Status.OK_STATUS;
 
166
            }
 
167
        };
 
168
        job.schedule();
 
169
 
 
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)
 
174
        {
 
175
            private ITmfTimestamp startTime = null;
 
176
            private ITmfTimestamp lastTime = null;
 
177
 
 
178
            @Override
 
179
            public void handleData(final ITmfEvent event) {
 
180
                super.handleData(event);
 
181
                if (event != null) {
 
182
                    final ITmfTimestamp timestamp = event.getTimestamp();
 
183
                    if (startTime == null) {
 
184
                        startTime = timestamp.clone();
 
185
                    }
 
186
                    lastTime = timestamp.clone();
 
187
 
 
188
                    // Update the trace status at regular intervals
 
189
                    if ((getNbRead() % fCheckpointInterval) == 0) {
 
190
                        updateTraceStatus();
 
191
                    }
 
192
                }
 
193
            }
 
194
 
 
195
            @Override
 
196
            public void handleSuccess() {
 
197
                updateTraceStatus();
 
198
            }
 
199
 
 
200
            @Override
 
201
            public void handleCompleted() {
 
202
                job.cancel();
 
203
                super.handleCompleted();
 
204
                fIsIndexing = false;
 
205
            }
 
206
 
 
207
            private void updateTraceStatus() {
 
208
                if (getNbRead() != 0) {
 
209
                    signalNewTimeRange(startTime, lastTime);
 
210
                }
 
211
            }
 
212
        };
 
213
 
 
214
        // Submit the request and wait for completion if required
 
215
        fTrace.sendRequest(fIndexingRequest);
 
216
        if (waitForCompletion) {
 
217
            try {
 
218
                fIndexingRequest.waitForCompletion();
 
219
            } catch (final InterruptedException e) {
 
220
            }
 
221
        }
 
222
    }
 
223
 
 
224
    /**
 
225
     * Notify the interested parties that the trace time range has changed
 
226
     * 
 
227
     * @param startTime the new start time
 
228
     * @param endTime the new end time
 
229
     */
 
230
    private void signalNewTimeRange(final ITmfTimestamp startTime, final ITmfTimestamp endTime) {
 
231
        fTrace.broadcast(new TmfTraceUpdatedSignal(fTrace, fTrace, new TmfTimeRange(startTime, endTime)));
 
232
    }
 
233
 
 
234
    // ------------------------------------------------------------------------
 
235
    // ITmfTraceIndexer - updateIndex
 
236
    // ------------------------------------------------------------------------
 
237
 
 
238
    /* (non-Javadoc)
 
239
     * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#updateIndex(org.eclipse.linuxtools.tmf.core.trace.ITmfContext, org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
 
240
     */
 
241
    @Override
 
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)));
 
250
            }
 
251
        }
 
252
    }
 
253
 
 
254
    // ------------------------------------------------------------------------
 
255
    // ITmfTraceIndexer - seekIndex
 
256
    // ------------------------------------------------------------------------
 
257
 
 
258
    /* (non-Javadoc)
 
259
     * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#seekIndex(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
 
260
     */
 
261
    @Override
 
262
    public synchronized ITmfContext seekIndex(final ITmfTimestamp timestamp) {
 
263
 
 
264
        // A null timestamp indicates to seek the first event
 
265
        if (timestamp == null) {
 
266
            return fTrace.seekEvent(0);
 
267
        }
 
268
 
 
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));
 
274
        if (index < 0) {
 
275
            index = Math.max(0, -(index + 2));
 
276
        }
 
277
 
 
278
        // Position the trace at the checkpoint
 
279
        return restoreCheckpoint(index);
 
280
    }
 
281
 
 
282
    /* (non-Javadoc)
 
283
     * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#seekIndex(long)
 
284
     */
 
285
    @Override
 
286
    public ITmfContext seekIndex(final long rank) {
 
287
 
 
288
        // A rank < 0 indicates to seek the first event
 
289
        if (rank < 0) {
 
290
            return fTrace.seekEvent(0);
 
291
        }
 
292
 
 
293
        // Find the checkpoint at or before the requested rank.
 
294
        final int index = (int) rank / fCheckpointInterval;
 
295
 
 
296
        // Position the trace at the checkpoint
 
297
        return restoreCheckpoint(index);
 
298
    }
 
299
 
 
300
    /**
 
301
     * Position the trace at the given checkpoint
 
302
     * 
 
303
     * @param checkpoint the checkpoint index
 
304
     * @return the corresponding context
 
305
     */
 
306
    private ITmfContext restoreCheckpoint(final int checkpoint) {
 
307
        ITmfLocation<?> location = null;
 
308
        int index = 0;
 
309
        synchronized (fTraceIndex) {
 
310
            if (!fTraceIndex.isEmpty()) {
 
311
                index = checkpoint;
 
312
                if (index >= fTraceIndex.size()) {
 
313
                    index = fTraceIndex.size() - 1;
 
314
                }
 
315
                return restoreContext(fTraceIndex.get(index).getContext());
 
316
            }
 
317
        }
 
318
        final ITmfContext context = fTrace.seekEvent(location);
 
319
        context.setRank((long) index * fCheckpointInterval);
 
320
        return context;
 
321
    }
 
322
 
 
323
    // ------------------------------------------------------------------------
 
324
    // Getters
 
325
    // ------------------------------------------------------------------------
 
326
 
 
327
    /**
 
328
     * @return the trace index
 
329
     */
 
330
    protected List<ITmfCheckpoint> getTraceIndex() {
 
331
        return fTraceIndex;
 
332
    }
 
333
 
 
334
    // ------------------------------------------------------------------------
 
335
    // Context conversion functions
 
336
    // ------------------------------------------------------------------------
 
337
 
 
338
    private ITmfContext shrinkContext(ITmfContext context) {
 
339
        if (context instanceof TmfExperimentContext) {
 
340
            return shrinkExpContext(context);
 
341
        }
 
342
        TmfContext ctx = new TmfContext(context.getLocation().clone(), context.getRank());
 
343
        return ctx;
 
344
    }
 
345
 
 
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;
 
353
        }
 
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;
 
361
        }
 
362
        return expCtx;
 
363
    }
 
364
 
 
365
    private ITmfContext restoreContext(ITmfContext context) {
 
366
        if (context instanceof TmfExperimentContext) {
 
367
            return restoreExpContext(context);
 
368
        }
 
369
        ITmfContext ctx = fTrace.seekEvent(context.getLocation());
 
370
        ctx.setRank(context.getRank());
 
371
        return ctx;
 
372
    }
 
373
 
 
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());
 
383
        }
 
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;
 
391
        }
 
392
        return ctx;
 
393
    }
 
394
}