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

« back to all changes in this revision

Viewing changes to lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/events/TmfEventsCache.java

  • Committer: Package Import Robot
  • Author(s): tony mancill
  • Date: 2013-05-13 21:43:22 UTC
  • mfrom: (1.2.1) (2.1.2 experimental)
  • Revision ID: package-import@ubuntu.com-20130513214322-6frgd9du1n0w2uo7
Tags: 1.2.1-1
* Team upload.
* New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*******************************************************************************
2
 
 * Copyright (c) 2011 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
 
 *   Patrick Tasse - Initial API and implementation
11
 
 ******************************************************************************/
12
 
 
13
 
package org.eclipse.linuxtools.tmf.ui.viewers.events;
14
 
 
15
 
import java.util.ArrayList;
16
 
import java.util.List;
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.internal.tmf.ui.Activator;
23
 
import org.eclipse.linuxtools.tmf.core.component.ITmfDataProvider;
24
 
import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
25
 
import org.eclipse.linuxtools.tmf.core.filter.ITmfFilter;
26
 
import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
27
 
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
28
 
 
29
 
/**
30
 
 * The generic TMF Events table events cache
31
 
 *
32
 
 * This can help avoid re-reading the trace when the user scrolls a window,
33
 
 * for example.
34
 
 *
35
 
 * @version 1.0
36
 
 * @author Patrick Tasse
37
 
 */
38
 
public class TmfEventsCache {
39
 
 
40
 
    /**
41
 
     * The generic TMF Events table cached event
42
 
     *
43
 
     * @version 1.0
44
 
     * @author Patrick Tasse
45
 
     */
46
 
    public static class CachedEvent {
47
 
        ITmfEvent event;
48
 
        long rank;
49
 
 
50
 
        /**
51
 
         * Constructor for new cached events.
52
 
         *
53
 
         * @param iTmfEvent
54
 
         *            The original trace event
55
 
         * @param rank
56
 
         *            The rank of this event in the trace
57
 
         */
58
 
        public CachedEvent (ITmfEvent iTmfEvent, long rank) {
59
 
            this.event = iTmfEvent;
60
 
            this.rank = rank;
61
 
        }
62
 
    }
63
 
 
64
 
    private final CachedEvent[] fCache;
65
 
    private int fCacheStartIndex = 0;
66
 
    private int fCacheEndIndex   = 0;
67
 
 
68
 
    private ITmfTrace<?> fTrace;
69
 
    private final TmfEventsTable fTable;
70
 
    private ITmfFilter fFilter;
71
 
    private final List<Integer> fFilterIndex = new ArrayList<Integer>(); // contains the event rank at each 'cache size' filtered events
72
 
 
73
 
    /**
74
 
     * Constructor for the event cache
75
 
     *
76
 
     * @param cacheSize
77
 
     *            The size of the cache, in number of events
78
 
     * @param table
79
 
     *            The Events table this cache will cover
80
 
     */
81
 
    public TmfEventsCache(int cacheSize, TmfEventsTable table) {
82
 
        fCache = new CachedEvent[cacheSize];
83
 
        fTable = table;
84
 
    }
85
 
 
86
 
    /**
87
 
     * Assign a new trace to this events cache. This clears the current
88
 
     * contents.
89
 
     *
90
 
     * @param trace
91
 
     *            The trace to assign.
92
 
     */
93
 
    public void setTrace(ITmfTrace<?> trace) {
94
 
        fTrace = trace;
95
 
        clear();
96
 
    }
97
 
 
98
 
    /**
99
 
     * Clear the current contents of this cache.
100
 
     */
101
 
    public synchronized void clear() {
102
 
        fCacheStartIndex = 0;
103
 
        fCacheEndIndex = 0;
104
 
        fFilterIndex.clear();
105
 
    }
106
 
 
107
 
    /**
108
 
     * Apply a filter on this event cache. This clears the current cache
109
 
     * contents.
110
 
     *
111
 
     * @param filter
112
 
     *            The ITmfFilter to apply.
113
 
     */
114
 
    public void applyFilter(ITmfFilter filter) {
115
 
        fFilter = filter;
116
 
        clear();
117
 
    }
118
 
 
119
 
    /**
120
 
     * Clear the current filter on this cache. This also clears the current
121
 
     * cache contents.
122
 
     */
123
 
    public void clearFilter() {
124
 
        fFilter = null;
125
 
        clear();
126
 
    }
127
 
 
128
 
    /**
129
 
     * Get an event from the cache. This will remove the event from the cache.
130
 
     *
131
 
     * FIXME this does not currently remove the event!
132
 
     *
133
 
     * @param index
134
 
     *            The index of this event in the cache
135
 
     * @return The cached event, or 'null' if there is no event at that index
136
 
     */
137
 
    public synchronized CachedEvent getEvent(int index) {
138
 
        if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {
139
 
            int i = index - fCacheStartIndex;
140
 
            return fCache[i];
141
 
        }
142
 
        populateCache(index);
143
 
        return null;
144
 
    }
145
 
 
146
 
    /**
147
 
     * Read an event, but without removing it from the cache.
148
 
     *
149
 
     * @param index
150
 
     *            Index of the event to peek
151
 
     * @return A reference to the event, or 'null' if there is no event at this
152
 
     *         index
153
 
     */
154
 
    public synchronized CachedEvent peekEvent(int index) {
155
 
        if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {
156
 
            int i = index - fCacheStartIndex;
157
 
            return fCache[i];
158
 
        }
159
 
        return null;
160
 
    }
161
 
 
162
 
    /**
163
 
     * Add a trace event to the cache.
164
 
     *
165
 
     * @param event
166
 
     *            The original trace event to be cached
167
 
     * @param rank
168
 
     *            The rank of this event in the trace
169
 
     * @param index
170
 
     *            The index this event will occupy in the cache
171
 
     */
172
 
    public synchronized void storeEvent(ITmfEvent event, long rank, int index) {
173
 
        if (index == fCacheEndIndex) {
174
 
            int i = index - fCacheStartIndex;
175
 
            if (i < fCache.length) {
176
 
                fCache[i] = new CachedEvent(event.clone(), rank);
177
 
                fCacheEndIndex++;
178
 
            }
179
 
        }
180
 
        if ((fFilter != null) && ((index % fCache.length) == 0)) {
181
 
            int i = index / fCache.length;
182
 
            fFilterIndex.add(i, Integer.valueOf((int) rank));
183
 
        }
184
 
    }
185
 
 
186
 
    /**
187
 
     * Get the cache index of an event from his rank in the trace. This will
188
 
     * take in consideration any filter that might be applied.
189
 
     *
190
 
     * @param rank
191
 
     *            The rank of the event in the trace
192
 
     * @return The position (index) this event should use once cached
193
 
     */
194
 
    @SuppressWarnings("unchecked")
195
 
    public int getFilteredEventIndex(final long rank) {
196
 
        int current;
197
 
        int startRank;
198
 
        TmfDataRequest<ITmfEvent> request;
199
 
        final ITmfFilter filter = fFilter;
200
 
        synchronized (this) {
201
 
            int start = 0;
202
 
            int end = fFilterIndex.size();
203
 
 
204
 
            if ((fCacheEndIndex - fCacheStartIndex) > 1) {
205
 
                if (rank < fCache[0].rank) {
206
 
                    end = (fCacheStartIndex / fCache.length) + 1;
207
 
                } else if (rank > fCache[fCacheEndIndex - fCacheStartIndex - 1].rank) {
208
 
                    start = fCacheEndIndex / fCache.length;
209
 
                } else {
210
 
                    for (int i = 0; i < (fCacheEndIndex - fCacheStartIndex); i++) {
211
 
                        if (fCache[i].rank >= rank) {
212
 
                            return fCacheStartIndex + i;
213
 
                        }
214
 
                    }
215
 
                    return fCacheEndIndex;
216
 
                }
217
 
            }
218
 
 
219
 
            current = (start + end) / 2;
220
 
            while (current != start) {
221
 
                if (rank < fFilterIndex.get(current)) {
222
 
                    end = current;
223
 
                    current = (start + end) / 2;
224
 
                } else {
225
 
                    start = current;
226
 
                    current = (start + end) / 2;
227
 
                }
228
 
            }
229
 
            startRank = fFilterIndex.size() > 0 ? fFilterIndex.get(current) : 0;
230
 
        }
231
 
 
232
 
        final int index = current * fCache.length;
233
 
 
234
 
        class DataRequest<T extends ITmfEvent> extends TmfDataRequest<T> {
235
 
            ITmfFilter fFilter;
236
 
            int fRank;
237
 
            int fIndex;
238
 
 
239
 
            DataRequest(Class<T> dataType, ITmfFilter filter, int start, int nbRequested) {
240
 
                super(dataType, start, nbRequested);
241
 
                fFilter = filter;
242
 
                fRank = start;
243
 
                fIndex = index;
244
 
            }
245
 
 
246
 
            @Override
247
 
            public void handleData(T event) {
248
 
                super.handleData(event);
249
 
                if (isCancelled()) {
250
 
                    return;
251
 
                }
252
 
                if (fRank >= rank) {
253
 
                    cancel();
254
 
                    return;
255
 
                }
256
 
                fRank++;
257
 
                if (fFilter.matches(event)) {
258
 
                    fIndex++;
259
 
                }
260
 
            }
261
 
 
262
 
            public int getFilteredIndex() {
263
 
                return fIndex;
264
 
            }
265
 
        }
266
 
 
267
 
        request = new DataRequest<ITmfEvent>(ITmfEvent.class, filter, startRank, TmfDataRequest.ALL_DATA);
268
 
        ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);
269
 
        try {
270
 
            request.waitForCompletion();
271
 
            return ((DataRequest<ITmfEvent>) request).getFilteredIndex();
272
 
        } catch (InterruptedException e) {
273
 
            Activator.getDefault().logError("Filter request interrupted!", e); //$NON-NLS-1$
274
 
        }
275
 
        return 0;
276
 
    }
277
 
 
278
 
    // ------------------------------------------------------------------------
279
 
    // Event cache population
280
 
    // ------------------------------------------------------------------------
281
 
 
282
 
    // The event fetching job
283
 
    private Job job;
284
 
    private synchronized void populateCache(final int index) {
285
 
 
286
 
        /* Check if the current job will fetch the requested event:
287
 
         * 1. The job must exist
288
 
         * 2. It must be running (i.e. not completed)
289
 
         * 3. The requested index must be within the cache range
290
 
         *
291
 
         * If the job meets these conditions, we simply exit.
292
 
         * Otherwise, we create a new job but we might have to cancel
293
 
         * an existing job for an obsolete range.
294
 
         */
295
 
        if (job != null) {
296
 
            if (job.getState() != Job.NONE) {
297
 
                if ((index >= fCacheStartIndex) && (index < (fCacheStartIndex + fCache.length))) {
298
 
                    return;
299
 
                }
300
 
                // The new index is out of the requested range
301
 
                // Kill the job and start a new one
302
 
                job.cancel();
303
 
            }
304
 
        }
305
 
 
306
 
        fCacheStartIndex = index;
307
 
        fCacheEndIndex   = index;
308
 
 
309
 
        job = new Job("Fetching Events") { //$NON-NLS-1$
310
 
            private int startIndex = index;
311
 
            private int skipCount = 0;
312
 
            @Override
313
 
            @SuppressWarnings("unchecked")
314
 
            protected IStatus run(final IProgressMonitor monitor) {
315
 
 
316
 
                int nbRequested;
317
 
                if (fFilter == null) {
318
 
                    nbRequested = fCache.length;
319
 
                } else {
320
 
                    nbRequested = TmfDataRequest.ALL_DATA;
321
 
                    int i = index / fCache.length;
322
 
                    if (i < fFilterIndex.size()) {
323
 
                        startIndex = fFilterIndex.get(i);
324
 
                        skipCount = index - (i * fCache.length);
325
 
                    }
326
 
                }
327
 
 
328
 
                TmfDataRequest<ITmfEvent> request = new TmfDataRequest<ITmfEvent>(ITmfEvent.class, startIndex, nbRequested) {
329
 
                    private int count = 0;
330
 
                    private long rank = startIndex;
331
 
                    @Override
332
 
                    public void handleData(ITmfEvent event) {
333
 
                        // If the job is canceled, cancel the request so waitForCompletion() will unlock
334
 
                        if (monitor.isCanceled()) {
335
 
                            cancel();
336
 
                            return;
337
 
                        }
338
 
                        super.handleData(event);
339
 
                        if (event != null) {
340
 
                            if (((fFilter == null) || fFilter.matches(event)) && (skipCount-- <= 0)) {
341
 
                                synchronized (TmfEventsCache.this) {
342
 
                                    fCache[count] = new CachedEvent(event.clone(), rank);
343
 
                                    count++;
344
 
                                    fCacheEndIndex++;
345
 
                                }
346
 
                                if (fFilter != null) {
347
 
                                    fTable.cacheUpdated(false);
348
 
                                }
349
 
                            }
350
 
                        }
351
 
                        if (count >= fCache.length) {
352
 
                            cancel();
353
 
                        } else if ((fFilter != null) && (count >= (fTable.getTable().getItemCount() - 3))) { // -1 for header row, -2 for top and bottom filter status rows
354
 
                            cancel();
355
 
                        }
356
 
                        rank++;
357
 
                    }
358
 
                };
359
 
 
360
 
                ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);
361
 
                try {
362
 
                    request.waitForCompletion();
363
 
                } catch (InterruptedException e) {
364
 
                    Activator.getDefault().logError("Wait for completion interrupted for populateCache ", e); //$NON-NLS-1$
365
 
                }
366
 
 
367
 
                fTable.cacheUpdated(true);
368
 
 
369
 
                // Flag the UI thread that the cache is ready
370
 
                if (monitor.isCanceled()) {
371
 
                    return Status.CANCEL_STATUS;
372
 
                }
373
 
                return Status.OK_STATUS;
374
 
            }
375
 
        };
376
 
        //job.setSystem(true);
377
 
        job.setPriority(Job.SHORT);
378
 
        job.schedule();
379
 
    }
380
 
 
381
 
}
 
1
/*******************************************************************************
 
2
 * Copyright (c) 2011 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
 *   Patrick Tasse - Initial API and implementation
 
11
 ******************************************************************************/
 
12
 
 
13
package org.eclipse.linuxtools.tmf.ui.viewers.events;
 
14
 
 
15
import java.util.ArrayList;
 
16
import java.util.List;
 
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.internal.tmf.ui.Activator;
 
23
import org.eclipse.linuxtools.tmf.core.component.ITmfDataProvider;
 
24
import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
 
25
import org.eclipse.linuxtools.tmf.core.filter.ITmfFilter;
 
26
import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
 
27
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
 
28
 
 
29
/**
 
30
 * The generic TMF Events table events cache
 
31
 *
 
32
 * This can help avoid re-reading the trace when the user scrolls a window,
 
33
 * for example.
 
34
 *
 
35
 * @version 1.0
 
36
 * @author Patrick Tasse
 
37
 */
 
38
public class TmfEventsCache {
 
39
 
 
40
    /**
 
41
     * The generic TMF Events table cached event
 
42
     *
 
43
     * @version 1.0
 
44
     * @author Patrick Tasse
 
45
     */
 
46
    public static class CachedEvent {
 
47
        ITmfEvent event;
 
48
        long rank;
 
49
 
 
50
        /**
 
51
         * Constructor for new cached events.
 
52
         *
 
53
         * @param iTmfEvent
 
54
         *            The original trace event
 
55
         * @param rank
 
56
         *            The rank of this event in the trace
 
57
         */
 
58
        public CachedEvent (ITmfEvent iTmfEvent, long rank) {
 
59
            this.event = iTmfEvent;
 
60
            this.rank = rank;
 
61
        }
 
62
    }
 
63
 
 
64
    private final CachedEvent[] fCache;
 
65
    private int fCacheStartIndex = 0;
 
66
    private int fCacheEndIndex   = 0;
 
67
 
 
68
    private ITmfTrace<?> fTrace;
 
69
    private final TmfEventsTable fTable;
 
70
    private ITmfFilter fFilter;
 
71
    private final List<Integer> fFilterIndex = new ArrayList<Integer>(); // contains the event rank at each 'cache size' filtered events
 
72
 
 
73
    /**
 
74
     * Constructor for the event cache
 
75
     *
 
76
     * @param cacheSize
 
77
     *            The size of the cache, in number of events
 
78
     * @param table
 
79
     *            The Events table this cache will cover
 
80
     */
 
81
    public TmfEventsCache(int cacheSize, TmfEventsTable table) {
 
82
        fCache = new CachedEvent[cacheSize];
 
83
        fTable = table;
 
84
    }
 
85
 
 
86
    /**
 
87
     * Assign a new trace to this events cache. This clears the current
 
88
     * contents.
 
89
     *
 
90
     * @param trace
 
91
     *            The trace to assign.
 
92
     */
 
93
    public void setTrace(ITmfTrace<?> trace) {
 
94
        fTrace = trace;
 
95
        clear();
 
96
    }
 
97
 
 
98
    /**
 
99
     * Clear the current contents of this cache.
 
100
     */
 
101
    public synchronized void clear() {
 
102
        fCacheStartIndex = 0;
 
103
        fCacheEndIndex = 0;
 
104
        fFilterIndex.clear();
 
105
    }
 
106
 
 
107
    /**
 
108
     * Apply a filter on this event cache. This clears the current cache
 
109
     * contents.
 
110
     *
 
111
     * @param filter
 
112
     *            The ITmfFilter to apply.
 
113
     */
 
114
    public void applyFilter(ITmfFilter filter) {
 
115
        fFilter = filter;
 
116
        clear();
 
117
    }
 
118
 
 
119
    /**
 
120
     * Clear the current filter on this cache. This also clears the current
 
121
     * cache contents.
 
122
     */
 
123
    public void clearFilter() {
 
124
        fFilter = null;
 
125
        clear();
 
126
    }
 
127
 
 
128
    /**
 
129
     * Get an event from the cache. This will remove the event from the cache.
 
130
     *
 
131
     * FIXME this does not currently remove the event!
 
132
     *
 
133
     * @param index
 
134
     *            The index of this event in the cache
 
135
     * @return The cached event, or 'null' if there is no event at that index
 
136
     */
 
137
    public synchronized CachedEvent getEvent(int index) {
 
138
        if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {
 
139
            int i = index - fCacheStartIndex;
 
140
            return fCache[i];
 
141
        }
 
142
        populateCache(index);
 
143
        return null;
 
144
    }
 
145
 
 
146
    /**
 
147
     * Read an event, but without removing it from the cache.
 
148
     *
 
149
     * @param index
 
150
     *            Index of the event to peek
 
151
     * @return A reference to the event, or 'null' if there is no event at this
 
152
     *         index
 
153
     */
 
154
    public synchronized CachedEvent peekEvent(int index) {
 
155
        if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {
 
156
            int i = index - fCacheStartIndex;
 
157
            return fCache[i];
 
158
        }
 
159
        return null;
 
160
    }
 
161
 
 
162
    /**
 
163
     * Add a trace event to the cache.
 
164
     *
 
165
     * @param event
 
166
     *            The original trace event to be cached
 
167
     * @param rank
 
168
     *            The rank of this event in the trace
 
169
     * @param index
 
170
     *            The index this event will occupy in the cache
 
171
     */
 
172
    public synchronized void storeEvent(ITmfEvent event, long rank, int index) {
 
173
        if (index == fCacheEndIndex) {
 
174
            int i = index - fCacheStartIndex;
 
175
            if (i < fCache.length) {
 
176
                fCache[i] = new CachedEvent(event.clone(), rank);
 
177
                fCacheEndIndex++;
 
178
            }
 
179
        }
 
180
        if ((fFilter != null) && ((index % fCache.length) == 0)) {
 
181
            int i = index / fCache.length;
 
182
            fFilterIndex.add(i, Integer.valueOf((int) rank));
 
183
        }
 
184
    }
 
185
 
 
186
    /**
 
187
     * Get the cache index of an event from his rank in the trace. This will
 
188
     * take in consideration any filter that might be applied.
 
189
     *
 
190
     * @param rank
 
191
     *            The rank of the event in the trace
 
192
     * @return The position (index) this event should use once cached
 
193
     */
 
194
    @SuppressWarnings("unchecked")
 
195
    public int getFilteredEventIndex(final long rank) {
 
196
        int current;
 
197
        int startRank;
 
198
        TmfDataRequest<ITmfEvent> request;
 
199
        final ITmfFilter filter = fFilter;
 
200
        synchronized (this) {
 
201
            int start = 0;
 
202
            int end = fFilterIndex.size();
 
203
 
 
204
            if ((fCacheEndIndex - fCacheStartIndex) > 1) {
 
205
                if (rank < fCache[0].rank) {
 
206
                    end = (fCacheStartIndex / fCache.length) + 1;
 
207
                } else if (rank > fCache[fCacheEndIndex - fCacheStartIndex - 1].rank) {
 
208
                    start = fCacheEndIndex / fCache.length;
 
209
                } else {
 
210
                    for (int i = 0; i < (fCacheEndIndex - fCacheStartIndex); i++) {
 
211
                        if (fCache[i].rank >= rank) {
 
212
                            return fCacheStartIndex + i;
 
213
                        }
 
214
                    }
 
215
                    return fCacheEndIndex;
 
216
                }
 
217
            }
 
218
 
 
219
            current = (start + end) / 2;
 
220
            while (current != start) {
 
221
                if (rank < fFilterIndex.get(current)) {
 
222
                    end = current;
 
223
                    current = (start + end) / 2;
 
224
                } else {
 
225
                    start = current;
 
226
                    current = (start + end) / 2;
 
227
                }
 
228
            }
 
229
            startRank = fFilterIndex.size() > 0 ? fFilterIndex.get(current) : 0;
 
230
        }
 
231
 
 
232
        final int index = current * fCache.length;
 
233
 
 
234
        class DataRequest<T extends ITmfEvent> extends TmfDataRequest<T> {
 
235
            ITmfFilter fFilter;
 
236
            int fRank;
 
237
            int fIndex;
 
238
 
 
239
            DataRequest(Class<T> dataType, ITmfFilter filter, int start, int nbRequested) {
 
240
                super(dataType, start, nbRequested);
 
241
                fFilter = filter;
 
242
                fRank = start;
 
243
                fIndex = index;
 
244
            }
 
245
 
 
246
            @Override
 
247
            public void handleData(T event) {
 
248
                super.handleData(event);
 
249
                if (isCancelled()) {
 
250
                    return;
 
251
                }
 
252
                if (fRank >= rank) {
 
253
                    cancel();
 
254
                    return;
 
255
                }
 
256
                fRank++;
 
257
                if (fFilter.matches(event)) {
 
258
                    fIndex++;
 
259
                }
 
260
            }
 
261
 
 
262
            public int getFilteredIndex() {
 
263
                return fIndex;
 
264
            }
 
265
        }
 
266
 
 
267
        request = new DataRequest<ITmfEvent>(ITmfEvent.class, filter, startRank, TmfDataRequest.ALL_DATA);
 
268
        ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);
 
269
        try {
 
270
            request.waitForCompletion();
 
271
            return ((DataRequest<ITmfEvent>) request).getFilteredIndex();
 
272
        } catch (InterruptedException e) {
 
273
            Activator.getDefault().logError("Filter request interrupted!", e); //$NON-NLS-1$
 
274
        }
 
275
        return 0;
 
276
    }
 
277
 
 
278
    // ------------------------------------------------------------------------
 
279
    // Event cache population
 
280
    // ------------------------------------------------------------------------
 
281
 
 
282
    // The event fetching job
 
283
    private Job job;
 
284
    private synchronized void populateCache(final int index) {
 
285
 
 
286
        /* Check if the current job will fetch the requested event:
 
287
         * 1. The job must exist
 
288
         * 2. It must be running (i.e. not completed)
 
289
         * 3. The requested index must be within the cache range
 
290
         *
 
291
         * If the job meets these conditions, we simply exit.
 
292
         * Otherwise, we create a new job but we might have to cancel
 
293
         * an existing job for an obsolete range.
 
294
         */
 
295
        if (job != null) {
 
296
            if (job.getState() != Job.NONE) {
 
297
                if ((index >= fCacheStartIndex) && (index < (fCacheStartIndex + fCache.length))) {
 
298
                    return;
 
299
                }
 
300
                // The new index is out of the requested range
 
301
                // Kill the job and start a new one
 
302
                job.cancel();
 
303
            }
 
304
        }
 
305
 
 
306
        fCacheStartIndex = index;
 
307
        fCacheEndIndex   = index;
 
308
 
 
309
        job = new Job("Fetching Events") { //$NON-NLS-1$
 
310
            private int startIndex = index;
 
311
            private int skipCount = 0;
 
312
            @Override
 
313
            @SuppressWarnings("unchecked")
 
314
            protected IStatus run(final IProgressMonitor monitor) {
 
315
 
 
316
                int nbRequested;
 
317
                if (fFilter == null) {
 
318
                    nbRequested = fCache.length;
 
319
                } else {
 
320
                    nbRequested = TmfDataRequest.ALL_DATA;
 
321
                    int i = index / fCache.length;
 
322
                    if (i < fFilterIndex.size()) {
 
323
                        startIndex = fFilterIndex.get(i);
 
324
                        skipCount = index - (i * fCache.length);
 
325
                    }
 
326
                }
 
327
 
 
328
                TmfDataRequest<ITmfEvent> request = new TmfDataRequest<ITmfEvent>(ITmfEvent.class, startIndex, nbRequested) {
 
329
                    private int count = 0;
 
330
                    private long rank = startIndex;
 
331
                    @Override
 
332
                    public void handleData(ITmfEvent event) {
 
333
                        // If the job is canceled, cancel the request so waitForCompletion() will unlock
 
334
                        if (monitor.isCanceled()) {
 
335
                            cancel();
 
336
                            return;
 
337
                        }
 
338
                        super.handleData(event);
 
339
                        if (event != null) {
 
340
                            if (((fFilter == null) || fFilter.matches(event)) && (skipCount-- <= 0)) {
 
341
                                synchronized (TmfEventsCache.this) {
 
342
                                    if (monitor.isCanceled()) {
 
343
                                        return;
 
344
                                    }
 
345
                                    fCache[count] = new CachedEvent(event.clone(), rank);
 
346
                                    count++;
 
347
                                    fCacheEndIndex++;
 
348
                                }
 
349
                                if (fFilter != null) {
 
350
                                    fTable.cacheUpdated(false);
 
351
                                }
 
352
                            }
 
353
                        }
 
354
                        if (count >= fCache.length) {
 
355
                            cancel();
 
356
                        } else if ((fFilter != null) && (count >= (fTable.getTable().getItemCount() - 3))) { // -1 for header row, -2 for top and bottom filter status rows
 
357
                            cancel();
 
358
                        }
 
359
                        rank++;
 
360
                    }
 
361
                };
 
362
 
 
363
                ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);
 
364
                try {
 
365
                    request.waitForCompletion();
 
366
                } catch (InterruptedException e) {
 
367
                    Activator.getDefault().logError("Wait for completion interrupted for populateCache ", e); //$NON-NLS-1$
 
368
                }
 
369
 
 
370
                fTable.cacheUpdated(true);
 
371
 
 
372
                // Flag the UI thread that the cache is ready
 
373
                if (monitor.isCanceled()) {
 
374
                    return Status.CANCEL_STATUS;
 
375
                }
 
376
                return Status.OK_STATUS;
 
377
            }
 
378
        };
 
379
        //job.setSystem(true);
 
380
        job.setPriority(Job.SHORT);
 
381
        job.schedule();
 
382
    }
 
383
 
 
384
}