Refactor TmfTrace and dependencies - introduce ITmfTraceIndexer
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / trace / TmfTraceIndexer.java
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.Collections;
16 import java.util.Vector;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.core.runtime.Status;
21 import org.eclipse.core.runtime.jobs.Job;
22 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
23 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
24 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
25 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
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
32 /**
33 * <b><u>TmfTraceIndexer</u></b>
34 * <p>
35 * A simple trace indexer that builds an array of trace checkpoints. Checkpoints
36 * are stored at fixed intervals (event rank) in 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 public class TmfTraceIndexer<T extends ITmfTrace<ITmfEvent>> implements ITmfTraceIndexer<T> {
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
52 /**
53 * The event trace to index
54 */
55 private final ITmfTrace<ITmfEvent> fTrace;
56
57 /**
58 * The interval between checkpoints
59 */
60 protected final int fCheckpointInterval;
61
62 /**
63 * The trace index. It is composed of checkpoints taken at intervals of
64 * fCheckpointInterval events.
65 */
66 protected final Vector<TmfCheckpoint> fTraceIndex;
67
68 // ------------------------------------------------------------------------
69 // Construction
70 // ------------------------------------------------------------------------
71
72 /**
73 * Basic constructor that uses the default trace block size as checkpoints
74 * intervals
75 *
76 * @param trace the trace to index
77 */
78 public TmfTraceIndexer(final ITmfTrace<ITmfEvent> trace) {
79 this(trace, TmfTrace.DEFAULT_BLOCK_SIZE);
80 }
81
82 /**
83 * Full trace indexer
84 *
85 * @param trace the trace to index
86 * @param interval the checkpoints interval
87 */
88 public TmfTraceIndexer(final ITmfTrace<ITmfEvent> trace, final int interval) {
89 fTrace = trace;
90 fCheckpointInterval = interval;
91 fTraceIndex = new Vector<TmfCheckpoint>();
92 }
93
94 // ------------------------------------------------------------------------
95 // ITmfTraceIndexer
96 // ------------------------------------------------------------------------
97
98 /* (non-Javadoc)
99 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTrace#indexTrace(boolean)
100 *
101 * The index is a list of contexts that point to events at regular interval
102 * (rank-wise) in the trace. After it is built, the index can be used to
103 * quickly access any event by rank or timestamp (using seekIndex()).
104 *
105 * The index is built simply by reading the trace
106 */
107 @Override
108 public void buildIndex(final boolean waitForCompletion) {
109
110 // The monitoring job
111 final Job job = new Job("Indexing " + fTrace.getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
112 @Override
113 protected IStatus run(final IProgressMonitor monitor) {
114 while (!monitor.isCanceled()) {
115 try {
116 Thread.sleep(100);
117 } catch (final InterruptedException e) {
118 return Status.OK_STATUS;
119 }
120 }
121 monitor.done();
122 return Status.OK_STATUS;
123 }
124 };
125 job.schedule();
126
127 // Clear the checkpoints
128 fTraceIndex.clear();
129
130 // Build a background request for all the trace data. The index is
131 // updated as we go by getNextEvent().
132 final ITmfEventRequest<ITmfEvent> request = new TmfEventRequest<ITmfEvent>(ITmfEvent.class, TmfTimeRange.ETERNITY,
133 TmfDataRequest.ALL_DATA, fCheckpointInterval, ITmfDataRequest.ExecutionType.BACKGROUND)
134 {
135 ITmfTimestamp startTime = null;
136 ITmfTimestamp lastTime = null;
137
138 @Override
139 public void handleData(final ITmfEvent event) {
140 super.handleData(event);
141 if (event != null) {
142 final ITmfTimestamp timestamp = event.getTimestamp();
143 if (startTime == null) {
144 startTime = timestamp.clone();
145 }
146 lastTime = timestamp.clone();
147
148 // Update the trace status at regular intervals
149 if ((getNbRead() % fCheckpointInterval) == 0) {
150 updateTraceStatus();
151 }
152 }
153 }
154
155 @Override
156 public void handleSuccess() {
157 updateTraceStatus();
158 }
159
160 @Override
161 public void handleCompleted() {
162 job.cancel();
163 super.handleCompleted();
164 }
165
166 private void updateTraceStatus() {
167 if (getNbRead() != 0) {
168 notifyListeners(startTime, lastTime);
169 }
170 }
171 };
172
173 // Submit the request and wait for completion if required
174 fTrace.sendRequest(request);
175 if (waitForCompletion) {
176 try {
177 request.waitForCompletion();
178 } catch (final InterruptedException e) {
179 }
180 }
181 }
182
183
184 /* (non-Javadoc)
185 * @see org.eclipse.linuxtools.tmf.core.trace.ITmfTraceIndexer#seekIndex(org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp)
186 */
187 @Override
188 public ITmfContext seekIndex(final ITmfTimestamp timestamp) {
189 // Adjust the timestamp if needed
190 ITmfTimestamp ts = timestamp;
191 if (ts == null) {
192 ts = TmfTimestamp.BIG_BANG;
193 }
194
195 // First, find the right checkpoint
196 int index = Collections.binarySearch(fTraceIndex, new TmfCheckpoint(ts, null));
197
198 // In the very likely case that the checkpoint was not found, bsearch
199 // returns its negated would-be location (not an offset...). From that
200 // index, we can then position the stream and get figure out the context.
201 if (index < 0) {
202 index = Math.max(0, -(index + 2));
203 }
204
205 // Position the trace at the checkpoint
206 ITmfLocation<?> location;
207 synchronized (fTraceIndex) {
208 if (!fTraceIndex.isEmpty()) {
209 if (index >= fTraceIndex.size()) {
210 index = fTraceIndex.size() - 1;
211 }
212 location = fTraceIndex.elementAt(index).getLocation();
213 } else {
214 location = null;
215 }
216 }
217 final ITmfContext context = fTrace.seekLocation(location);
218 context.setRank(index * fCheckpointInterval);
219
220 return context;
221 }
222
223 @Override
224 public ITmfContext seekIndex(final long rank) {
225
226 // Position the stream at the previous checkpoint
227 int index = (int) rank / fCheckpointInterval;
228 ITmfLocation<?> location;
229 synchronized (fTraceIndex) {
230 if (fTraceIndex.isEmpty()) {
231 location = null;
232 } else {
233 if (index >= fTraceIndex.size()) {
234 index = fTraceIndex.size() - 1;
235 }
236 location = fTraceIndex.elementAt(index).getLocation();
237 }
238 }
239
240 final ITmfContext context = fTrace.seekLocation(location);
241 final long pos = index * fCheckpointInterval;
242 context.setRank(pos);
243
244 return context;
245 }
246
247 private void notifyListeners(final ITmfTimestamp startTime, final ITmfTimestamp endTime) {
248 fTrace.broadcast(new TmfTraceUpdatedSignal(fTrace, fTrace, new TmfTimeRange(startTime, endTime)));
249 }
250
251 @Override
252 public void updateIndex(final ITmfContext context, final long rank, final ITmfTimestamp timestamp) {
253 if ((rank % fCheckpointInterval) == 0) {
254 // Determine the table position
255 final long position = rank / fCheckpointInterval;
256 // Add new entry at proper location (if empty)
257 if (fTraceIndex.size() == position) {
258 final ITmfLocation<?> location = context.getLocation().clone();
259 fTraceIndex.add(new TmfCheckpoint(timestamp.clone(), location));
260 // System.out.println(getName() + "[" + (fCheckpoints.size() - 1) + "] " + timestamp + ", " + location.toString());
261 }
262 }
263 }
264
265 }
This page took 0.043254 seconds and 5 git commands to generate.