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