Remove Linux Tools URL from LTTng category.xml file
[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
9fa32496 16import java.util.List;\r
2d55fd20
FC
17\r
18import org.eclipse.core.runtime.IProgressMonitor;\r
19import org.eclipse.core.runtime.IStatus;\r
20import org.eclipse.core.runtime.Status;\r
21import org.eclipse.core.runtime.jobs.Job;\r
8fd82db5 22import org.eclipse.linuxtools.internal.tmf.ui.Activator;\r
6c13869b 23import org.eclipse.linuxtools.tmf.core.component.ITmfDataProvider;\r
ce2388e0 24import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;\r
6c13869b
FC
25import org.eclipse.linuxtools.tmf.core.filter.ITmfFilter;\r
26import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;\r
27import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;\r
2d55fd20 28\r
00511ef2
FC
29/**\r
30 * The generic TMF Events table events cache\r
013a5f1c
AM
31 *\r
32 * This can help avoid re-reading the trace when the user scrolls a window,\r
33 * for example.\r
34 *\r
00511ef2
FC
35 * @version 1.0\r
36 * @author Patrick Tasse\r
37 */\r
2d55fd20
FC
38public class TmfEventsCache {\r
39\r
00511ef2
FC
40 /**\r
41 * The generic TMF Events table cached event\r
013a5f1c 42 *\r
00511ef2
FC
43 * @version 1.0\r
44 * @author Patrick Tasse\r
45 */\r
b389de1a
PT
46 public static class CachedEvent {\r
47 ITmfEvent event;\r
48 long rank;\r
2d55fd20 49\r
013a5f1c
AM
50 /**\r
51 * Constructor for new cached events.\r
52 *\r
53 * @param iTmfEvent\r
54 * The original trace event\r
55 * @param rank\r
56 * The rank of this event in the trace\r
57 */\r
b389de1a
PT
58 public CachedEvent (ITmfEvent iTmfEvent, long rank) {\r
59 this.event = iTmfEvent;\r
60 this.rank = rank;\r
61 }\r
62 }\r
2d55fd20 63\r
ce2388e0 64 private final CachedEvent[] fCache;\r
2d55fd20
FC
65 private int fCacheStartIndex = 0;\r
66 private int fCacheEndIndex = 0;\r
67\r
5d3e8747 68 private ITmfTrace<?> fTrace;\r
ce2388e0 69 private final TmfEventsTable fTable;\r
2d55fd20 70 private ITmfFilter fFilter;\r
9fa32496 71 private final List<Integer> fFilterIndex = new ArrayList<Integer>(); // contains the event rank at each 'cache size' filtered events\r
2d55fd20 72\r
013a5f1c
AM
73 /**\r
74 * Constructor for the event cache\r
75 *\r
76 * @param cacheSize\r
77 * The size of the cache, in number of events\r
78 * @param table\r
79 * The Events table this cache will cover\r
80 */\r
2d55fd20 81 public TmfEventsCache(int cacheSize, TmfEventsTable table) {\r
b389de1a
PT
82 fCache = new CachedEvent[cacheSize];\r
83 fTable = table;\r
2d55fd20 84 }\r
ce2388e0 85\r
013a5f1c
AM
86 /**\r
87 * Assign a new trace to this events cache. This clears the current\r
88 * contents.\r
89 *\r
90 * @param trace\r
91 * The trace to assign.\r
92 */\r
5d3e8747 93 public void setTrace(ITmfTrace<?> trace) {\r
b389de1a
PT
94 fTrace = trace;\r
95 clear();\r
2d55fd20 96 }\r
ce2388e0 97\r
013a5f1c
AM
98 /**\r
99 * Clear the current contents of this cache.\r
100 */\r
5a5c2fc7 101 public synchronized void clear() {\r
b389de1a
PT
102 fCacheStartIndex = 0;\r
103 fCacheEndIndex = 0;\r
104 fFilterIndex.clear();\r
2d55fd20
FC
105 }\r
106\r
013a5f1c
AM
107 /**\r
108 * Apply a filter on this event cache. This clears the current cache\r
109 * contents.\r
110 *\r
111 * @param filter\r
112 * The ITmfFilter to apply.\r
113 */\r
2d55fd20 114 public void applyFilter(ITmfFilter filter) {\r
b389de1a
PT
115 fFilter = filter;\r
116 clear();\r
2d55fd20 117 }\r
ce2388e0 118\r
013a5f1c
AM
119 /**\r
120 * Clear the current filter on this cache. This also clears the current\r
121 * cache contents.\r
122 */\r
2d55fd20 123 public void clearFilter() {\r
b389de1a
PT
124 fFilter = null;\r
125 clear();\r
2d55fd20 126 }\r
ce2388e0 127\r
013a5f1c
AM
128 /**\r
129 * Get an event from the cache. This will remove the event from the cache.\r
130 *\r
131 * FIXME this does not currently remove the event!\r
132 *\r
133 * @param index\r
134 * The index of this event in the cache\r
135 * @return The cached event, or 'null' if there is no event at that index\r
136 */\r
5a5c2fc7 137 public synchronized CachedEvent getEvent(int index) {\r
2d55fd20
FC
138 if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {\r
139 int i = index - fCacheStartIndex;\r
140 return fCache[i];\r
141 }\r
142 populateCache(index);\r
b389de1a 143 return null;\r
2d55fd20
FC
144 }\r
145\r
013a5f1c
AM
146 /**\r
147 * Read an event, but without removing it from the cache.\r
148 *\r
149 * @param index\r
150 * Index of the event to peek\r
151 * @return A reference to the event, or 'null' if there is no event at this\r
152 * index\r
153 */\r
5a5c2fc7 154 public synchronized CachedEvent peekEvent(int index) {\r
2d55fd20
FC
155 if ((index >= fCacheStartIndex) && (index < fCacheEndIndex)) {\r
156 int i = index - fCacheStartIndex;\r
157 return fCache[i];\r
158 }\r
b389de1a 159 return null;\r
2d55fd20 160 }\r
ce2388e0 161\r
013a5f1c
AM
162 /**\r
163 * Add a trace event to the cache.\r
164 *\r
165 * @param event\r
166 * The original trace event to be cached\r
167 * @param rank\r
168 * The rank of this event in the trace\r
169 * @param index\r
170 * The index this event will occupy in the cache\r
171 */\r
ce2388e0 172 public synchronized void storeEvent(ITmfEvent event, long rank, int index) {\r
b389de1a
PT
173 if (index == fCacheEndIndex) {\r
174 int i = index - fCacheStartIndex;\r
175 if (i < fCache.length) {\r
176 fCache[i] = new CachedEvent(event.clone(), rank);\r
177 fCacheEndIndex++;\r
178 }\r
179 }\r
180 if ((fFilter != null) && ((index % fCache.length) == 0)) {\r
181 int i = index / fCache.length;\r
182 fFilterIndex.add(i, Integer.valueOf((int) rank));\r
183 }\r
2d55fd20 184 }\r
ce2388e0 185\r
013a5f1c
AM
186 /**\r
187 * Get the cache index of an event from his rank in the trace. This will\r
188 * take in consideration any filter that might be applied.\r
189 *\r
190 * @param rank\r
191 * The rank of the event in the trace\r
192 * @return The position (index) this event should use once cached\r
193 */\r
2d55fd20 194 @SuppressWarnings("unchecked")\r
b389de1a
PT
195 public int getFilteredEventIndex(final long rank) {\r
196 int current;\r
197 int startRank;\r
198 TmfDataRequest<ITmfEvent> request;\r
199 final ITmfFilter filter = fFilter;\r
200 synchronized (this) {\r
201 int start = 0;\r
202 int end = fFilterIndex.size();\r
203\r
204 if ((fCacheEndIndex - fCacheStartIndex) > 1) {\r
205 if (rank < fCache[0].rank) {\r
206 end = (fCacheStartIndex / fCache.length) + 1;\r
207 } else if (rank > fCache[fCacheEndIndex - fCacheStartIndex - 1].rank) {\r
208 start = fCacheEndIndex / fCache.length;\r
209 } else {\r
210 for (int i = 0; i < (fCacheEndIndex - fCacheStartIndex); i++) {\r
211 if (fCache[i].rank >= rank) {\r
212 return fCacheStartIndex + i;\r
213 }\r
214 }\r
215 return fCacheEndIndex;\r
216 }\r
217 }\r
218\r
219 current = (start + end) / 2;\r
220 while (current != start) {\r
221 if (rank < fFilterIndex.get(current)) {\r
222 end = current;\r
223 current = (start + end) / 2;\r
224 } else {\r
225 start = current;\r
226 current = (start + end) / 2;\r
227 }\r
228 }\r
229 startRank = fFilterIndex.size() > 0 ? fFilterIndex.get(current) : 0;\r
230 }\r
231\r
232 final int index = current * fCache.length;\r
233\r
234 class DataRequest<T extends ITmfEvent> extends TmfDataRequest<T> {\r
235 ITmfFilter fFilter;\r
236 int fRank;\r
237 int fIndex;\r
238\r
239 DataRequest(Class<T> dataType, ITmfFilter filter, int start, int nbRequested) {\r
240 super(dataType, start, nbRequested);\r
241 fFilter = filter;\r
242 fRank = start;\r
243 fIndex = index;\r
244 }\r
245\r
246 @Override\r
247 public void handleData(T event) {\r
248 super.handleData(event);\r
249 if (isCancelled()) {\r
ce2388e0
FC
250 return;\r
251 }\r
b389de1a
PT
252 if (fRank >= rank) {\r
253 cancel();\r
254 return;\r
255 }\r
256 fRank++;\r
257 if (fFilter.matches(event)) {\r
258 fIndex++;\r
259 }\r
260 }\r
261\r
262 public int getFilteredIndex() {\r
263 return fIndex;\r
2d55fd20 264 }\r
b389de1a
PT
265 }\r
266\r
267 request = new DataRequest<ITmfEvent>(ITmfEvent.class, filter, startRank, TmfDataRequest.ALL_DATA);\r
268 ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);\r
269 try {\r
270 request.waitForCompletion();\r
271 return ((DataRequest<ITmfEvent>) request).getFilteredIndex();\r
272 } catch (InterruptedException e) {\r
273 Activator.getDefault().logError("Filter request interrupted!", e); //$NON-NLS-1$\r
274 }\r
275 return 0;\r
2d55fd20 276 }\r
ce2388e0 277\r
2d55fd20
FC
278 // ------------------------------------------------------------------------\r
279 // Event cache population\r
280 // ------------------------------------------------------------------------\r
ce2388e0 281\r
2d55fd20
FC
282 // The event fetching job\r
283 private Job job;\r
284 private synchronized void populateCache(final int index) {\r
285\r
286 /* Check if the current job will fetch the requested event:\r
287 * 1. The job must exist\r
288 * 2. It must be running (i.e. not completed)\r
289 * 3. The requested index must be within the cache range\r
ce2388e0 290 *\r
2d55fd20
FC
291 * If the job meets these conditions, we simply exit.\r
292 * Otherwise, we create a new job but we might have to cancel\r
293 * an existing job for an obsolete range.\r
294 */\r
295 if (job != null) {\r
296 if (job.getState() != Job.NONE) {\r
ce2388e0 297 if ((index >= fCacheStartIndex) && (index < (fCacheStartIndex + fCache.length))) {\r
2d55fd20
FC
298 return;\r
299 }\r
300 // The new index is out of the requested range\r
301 // Kill the job and start a new one\r
302 job.cancel();\r
303 }\r
304 }\r
ce2388e0 305\r
2d55fd20
FC
306 fCacheStartIndex = index;\r
307 fCacheEndIndex = index;\r
308\r
309 job = new Job("Fetching Events") { //$NON-NLS-1$\r
b389de1a
PT
310 private int startIndex = index;\r
311 private int skipCount = 0;\r
2d55fd20
FC
312 @Override\r
313 @SuppressWarnings("unchecked")\r
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
FC
327\r
328 TmfDataRequest<ITmfEvent> request = new TmfDataRequest<ITmfEvent>(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
ce2388e0 360 ((ITmfDataProvider<ITmfEvent>) 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.050622 seconds and 5 git commands to generate.