Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
61759503 | 2 | * Copyright (c) 2009, 2013 Ericsson |
0283f7ff | 3 | * |
8c8bf09f ASL |
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 | |
0283f7ff | 8 | * |
8c8bf09f ASL |
9 | * Contributors: |
10 | * Francois Chouinard - Initial API and implementation | |
9765b9f1 | 11 | * Alexandre Montplaisir - Consolidated constructors |
8c8bf09f ASL |
12 | *******************************************************************************/ |
13 | ||
6c13869b | 14 | package org.eclipse.linuxtools.tmf.core.request; |
8c8bf09f | 15 | |
5419a136 AM |
16 | import java.util.concurrent.CountDownLatch; |
17 | ||
5500a7f0 | 18 | import org.eclipse.linuxtools.internal.tmf.core.TmfCoreTracer; |
72f1e62a | 19 | import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; |
8c8bf09f ASL |
20 | |
21 | /** | |
9765b9f1 AM |
22 | * TmfDataRequests are used to obtain blocks of contiguous data from a data |
23 | * provider. Open ranges can be used, especially for continuous streaming. | |
8c8bf09f | 24 | * <p> |
9765b9f1 AM |
25 | * The request is processed asynchronously by a TmfProvider and, as blocks of |
26 | * data become available, handleData() is invoked synchronously for each block. | |
27 | * Upon return, the data instances go out of scope and become eligible for gc. | |
28 | * It is is thus the responsibility of the requester to either clone or keep a | |
29 | * reference to the data it wishes to track specifically. | |
8c8bf09f | 30 | * <p> |
9765b9f1 AM |
31 | * This data block approach is used to avoid busting the heap for very large |
32 | * trace files. The block size is configurable. | |
8c8bf09f | 33 | * <p> |
9765b9f1 AM |
34 | * The TmfProvider indicates that the request is completed by calling done(). |
35 | * The request can be canceled at any time with cancel(). | |
8c8bf09f ASL |
36 | * <p> |
37 | * Typical usage: | |
0283f7ff | 38 | * |
12c155f5 FC |
39 | * <pre> |
40 | * <code><i>TmfTimeWindow range = new TmfTimewindow(...); | |
41 | * TmfDataRequest<DataType[]> request = new TmfDataRequest<DataType[]>(DataType.class, 0, NB_EVENTS, BLOCK_SIZE) { | |
42 | * public void handleData() { | |
43 | * DataType[] data = request.getData(); | |
44 | * for (DataType e : data) { | |
45 | * // do something | |
46 | * } | |
47 | * } | |
48 | * public void handleSuccess() { | |
49 | * // do something | |
50 | * } | |
51 | * } | |
52 | * public void handleFailure() { | |
53 | * // do something | |
54 | * } | |
55 | * } | |
56 | * public void handleCancel() { | |
57 | * // do something | |
58 | * } | |
59 | * } | |
60 | * }; | |
61 | * fProcessor.process(request, true); | |
62 | * </i></code> | |
63 | * </pre> | |
0283f7ff | 64 | * |
9765b9f1 AM |
65 | * TODO: Consider decoupling from "time range", "rank", etc and for the more |
66 | * generic notion of "criteria". This would allow to extend for "time range", | |
67 | * etc instead of providing specialized constructors. This also means removing | |
68 | * the criteria info from the data structure (with the possible exception of | |
69 | * fNbRequested). The nice thing about it is that it would prepare us well for | |
70 | * the coming generation of analysis tools. | |
0283f7ff | 71 | * |
0ab46cd3 | 72 | * TODO: Implement request failures (codes, etc...) |
0283f7ff | 73 | * |
5419a136 | 74 | * @version 1.0 |
8fd82db5 | 75 | * @author Francois Chouinard |
8c8bf09f | 76 | */ |
5419a136 | 77 | public abstract class TmfDataRequest implements ITmfDataRequest { |
8c8bf09f | 78 | |
e31e01e8 | 79 | // ------------------------------------------------------------------------ |
8c8bf09f | 80 | // Constants |
e31e01e8 | 81 | // ------------------------------------------------------------------------ |
8c8bf09f | 82 | |
063f0d27 | 83 | /** The request count for all the events */ |
e31e01e8 | 84 | public static final int ALL_DATA = Integer.MAX_VALUE; |
12c155f5 | 85 | |
5419a136 AM |
86 | private static int fRequestNumber = 0; |
87 | ||
e31e01e8 | 88 | // ------------------------------------------------------------------------ |
8c8bf09f | 89 | // Attributes |
e31e01e8 | 90 | // ------------------------------------------------------------------------ |
8c8bf09f | 91 | |
5419a136 AM |
92 | private final Class<? extends ITmfEvent> fDataType; |
93 | private final ExecutionType fExecType; | |
94 | ||
95 | /** A unique request ID */ | |
96 | private final int fRequestId; | |
97 | ||
98 | /** The index (rank) of the requested event */ | |
99 | protected long fIndex; | |
100 | ||
101 | /** The number of requested events (ALL_DATA for all) */ | |
102 | protected int fNbRequested; | |
6f4e8ec0 | 103 | |
5419a136 AM |
104 | /** The number of reads so far */ |
105 | private int fNbRead; | |
106 | ||
107 | private final CountDownLatch startedLatch = new CountDownLatch(1); | |
108 | private final CountDownLatch completedLatch = new CountDownLatch(1); | |
109 | private boolean fRequestRunning; | |
110 | private boolean fRequestCompleted; | |
111 | private boolean fRequestFailed; | |
112 | private boolean fRequestCanceled; | |
113 | ||
e31e01e8 | 114 | // ------------------------------------------------------------------------ |
8c8bf09f | 115 | // Constructors |
e31e01e8 | 116 | // ------------------------------------------------------------------------ |
8c8bf09f | 117 | |
5419a136 AM |
118 | /** |
119 | * Resets the request counter (used for testing) | |
120 | */ | |
121 | public static void reset() { | |
122 | fRequestNumber = 0; | |
123 | } | |
124 | ||
0d9a6d76 FC |
125 | /** |
126 | * Request 'n' events of a given type from the given index (given priority). | |
127 | * Events are returned in blocks of the given size. | |
0283f7ff | 128 | * |
9765b9f1 AM |
129 | * @param dataType |
130 | * The requested data type. | |
131 | * @param index | |
132 | * The index of the first event to retrieve. Use '0' to start at | |
133 | * the beginning of the trace. | |
134 | * @param nbRequested | |
135 | * The number of events requested. You can use | |
136 | * {@link TmfDataRequest#ALL_DATA} to specify you want all events | |
137 | * in the trace. | |
9765b9f1 AM |
138 | * @param priority |
139 | * The requested execution priority. | |
0d9a6d76 | 140 | */ |
9765b9f1 AM |
141 | public TmfDataRequest(Class<? extends ITmfEvent> dataType, |
142 | long index, | |
143 | int nbRequested, | |
9765b9f1 | 144 | ExecutionType priority) { |
5419a136 AM |
145 | fRequestId = fRequestNumber++; |
146 | fDataType = dataType; | |
147 | fIndex = index; | |
148 | fNbRequested = nbRequested; | |
5419a136 AM |
149 | fExecType = priority; |
150 | fNbRead = 0; | |
151 | ||
152 | fRequestRunning = false; | |
153 | fRequestCompleted = false; | |
154 | fRequestFailed = false; | |
155 | fRequestCanceled = false; | |
beae214a | 156 | |
5500a7f0 | 157 | if (!(this instanceof ITmfEventRequest) && TmfCoreTracer.isRequestTraced()) { |
90891c08 FC |
158 | String type = getClass().getName(); |
159 | type = type.substring(type.lastIndexOf('.') + 1); | |
160 | @SuppressWarnings("nls") | |
0283f7ff FC |
161 | String message = "CREATED " |
162 | + (getExecType() == ITmfDataRequest.ExecutionType.BACKGROUND ? "(BG)" : "(FG)") | |
90891c08 FC |
163 | + " Type=" + type + " Index=" + getIndex() + " NbReq=" + getNbRequested() |
164 | + " DataType=" + getDataType().getSimpleName(); | |
5500a7f0 | 165 | TmfCoreTracer.traceRequest(this, message); |
90891c08 | 166 | } |
2fb2eb37 FC |
167 | } |
168 | ||
e31e01e8 | 169 | // ------------------------------------------------------------------------ |
165c977c | 170 | // Accessors |
e31e01e8 | 171 | // ------------------------------------------------------------------------ |
8c8bf09f | 172 | |
5419a136 AM |
173 | /** |
174 | * @return the request ID | |
175 | */ | |
176 | @Override | |
177 | public int getRequestId() { | |
178 | return fRequestId; | |
179 | } | |
180 | ||
12c155f5 FC |
181 | /** |
182 | * @return the index of the first event requested | |
183 | */ | |
184 | @Override | |
9e0640dc | 185 | public long getIndex() { |
5419a136 | 186 | return fIndex; |
12c155f5 FC |
187 | } |
188 | ||
189 | /** | |
0d9a6d76 | 190 | * @return the execution type (priority) |
12c155f5 FC |
191 | */ |
192 | @Override | |
193 | public ExecutionType getExecType() { | |
5419a136 | 194 | return fExecType; |
12c155f5 | 195 | } |
550d787e | 196 | |
5419a136 AM |
197 | /** |
198 | * @return the number of requested events (ALL_DATA = all) | |
8c8bf09f | 199 | */ |
d4011df2 | 200 | @Override |
5419a136 AM |
201 | public int getNbRequested() { |
202 | return fNbRequested; | |
8c8bf09f ASL |
203 | } |
204 | ||
660c9e60 FC |
205 | /** |
206 | * @return the number of events read so far | |
207 | */ | |
d4011df2 | 208 | @Override |
12c155f5 | 209 | public synchronized int getNbRead() { |
5419a136 AM |
210 | return fNbRead; |
211 | } | |
212 | ||
213 | /** | |
214 | * @return indicates if the request is currently running | |
215 | */ | |
216 | @Override | |
217 | public synchronized boolean isRunning() { | |
218 | return fRequestRunning; | |
219 | } | |
220 | ||
221 | /** | |
222 | * @return indicates if the request is completed | |
223 | */ | |
224 | @Override | |
225 | public synchronized boolean isCompleted() { | |
226 | return fRequestCompleted; | |
227 | } | |
228 | ||
229 | /** | |
230 | * @return indicates if the request has failed | |
231 | */ | |
232 | @Override | |
233 | public synchronized boolean isFailed() { | |
234 | return fRequestFailed; | |
235 | } | |
236 | ||
237 | /** | |
238 | * @return indicates if the request is canceled | |
239 | */ | |
240 | @Override | |
241 | public synchronized boolean isCancelled() { | |
242 | return fRequestCanceled; | |
8c8bf09f ASL |
243 | } |
244 | ||
e31e01e8 FC |
245 | /** |
246 | * @return the requested data type | |
247 | */ | |
d4011df2 | 248 | @Override |
6256d8ad | 249 | public Class<? extends ITmfEvent> getDataType() { |
5419a136 | 250 | return fDataType; |
e31e01e8 FC |
251 | } |
252 | ||
a79913eb FC |
253 | // ------------------------------------------------------------------------ |
254 | // Setters | |
255 | // ------------------------------------------------------------------------ | |
256 | ||
257 | /** | |
258 | * this method is called by the event provider to set the index corresponding to the time range start time | |
0283f7ff | 259 | * |
12c155f5 FC |
260 | * @param index |
261 | * the start time index | |
a79913eb | 262 | */ |
12c155f5 | 263 | protected void setIndex(int index) { |
5419a136 | 264 | fIndex = index; |
a79913eb FC |
265 | } |
266 | ||
e31e01e8 | 267 | // ------------------------------------------------------------------------ |
5419a136 | 268 | // Operators |
e31e01e8 | 269 | // ------------------------------------------------------------------------ |
8c8bf09f | 270 | |
12c155f5 | 271 | /** |
0d9a6d76 FC |
272 | * Handle incoming data, one event at a time i.e. this method is invoked |
273 | * for every data item obtained by the request. | |
0283f7ff | 274 | * |
0d9a6d76 FC |
275 | * - Data items are received in the order they appear in the stream |
276 | * - Called by the request processor, in its execution thread, every time | |
277 | * a block of data becomes available. | |
278 | * - Request processor performs a synchronous call to handleData() i.e. | |
279 | * its execution threads holds until handleData() returns. | |
280 | * - Original data items are disposed of on return i.e. keep a reference | |
281 | * (or a copy) if some persistence is needed between invocations. | |
282 | * - When there is no more data, done() is called. | |
0283f7ff | 283 | * |
0d9a6d76 | 284 | * @param data a piece of data |
8c8bf09f | 285 | */ |
d4011df2 | 286 | @Override |
6256d8ad | 287 | public void handleData(ITmfEvent data) { |
5419a136 AM |
288 | if (data != null) { |
289 | fNbRead++; | |
290 | } | |
291 | } | |
292 | ||
293 | @Override | |
294 | public void handleStarted() { | |
295 | if (TmfCoreTracer.isRequestTraced()) { | |
296 | TmfCoreTracer.traceRequest(this, "STARTED"); //$NON-NLS-1$ | |
297 | } | |
298 | } | |
299 | ||
300 | /** | |
301 | * Handle the completion of the request. It is called when there is no | |
302 | * more data available either because: | |
303 | * - the request completed normally | |
304 | * - the request failed | |
305 | * - the request was canceled | |
306 | * | |
307 | * As a convenience, handleXXXX methods are provided. They are meant to be | |
308 | * overridden by the application if it needs to handle these conditions. | |
309 | */ | |
310 | @Override | |
311 | public void handleCompleted() { | |
312 | boolean requestFailed = false; | |
313 | boolean requestCanceled = false; | |
314 | synchronized (this) { | |
315 | requestFailed = fRequestFailed; | |
316 | requestCanceled = fRequestCanceled; | |
317 | } | |
318 | ||
319 | if (requestFailed) { | |
320 | handleFailure(); | |
321 | } else if (requestCanceled) { | |
322 | handleCancel(); | |
323 | } else { | |
324 | handleSuccess(); | |
325 | } | |
326 | if (TmfCoreTracer.isRequestTraced()) { | |
327 | TmfCoreTracer.traceRequest(this, "COMPLETED (" + fNbRead + " events read)"); //$NON-NLS-1$ //$NON-NLS-2$ | |
328 | } | |
0ab46cd3 FC |
329 | } |
330 | ||
5419a136 AM |
331 | @Override |
332 | public void handleSuccess() { | |
333 | if (TmfCoreTracer.isRequestTraced()) { | |
334 | TmfCoreTracer.traceRequest(this, "SUCCEEDED"); //$NON-NLS-1$ | |
335 | } | |
336 | } | |
337 | ||
338 | @Override | |
339 | public void handleFailure() { | |
340 | if (TmfCoreTracer.isRequestTraced()) { | |
341 | TmfCoreTracer.traceRequest(this, "FAILED"); //$NON-NLS-1$ | |
342 | } | |
343 | } | |
344 | ||
345 | @Override | |
346 | public void handleCancel() { | |
347 | if (TmfCoreTracer.isRequestTraced()) { | |
348 | TmfCoreTracer.traceRequest(this, "CANCELLED"); //$NON-NLS-1$ | |
349 | } | |
350 | } | |
351 | ||
352 | /** | |
353 | * To suspend the client thread until the request starts (or is canceled). | |
354 | * | |
355 | * @throws InterruptedException | |
356 | * If the thread was interrupted while waiting | |
357 | */ | |
358 | public void waitForStart() throws InterruptedException { | |
359 | while (!fRequestRunning) { | |
360 | startedLatch.await(); | |
361 | } | |
362 | } | |
363 | ||
364 | /** | |
365 | * To suspend the client thread until the request completes (or is | |
366 | * canceled). | |
063f0d27 | 367 | * |
5419a136 AM |
368 | * @throws InterruptedException |
369 | * If the thread was interrupted while waiting | |
370 | */ | |
371 | @Override | |
372 | public void waitForCompletion() throws InterruptedException { | |
373 | while (!fRequestCompleted) { | |
374 | completedLatch.await(); | |
375 | } | |
376 | } | |
377 | ||
378 | /** | |
379 | * Called by the request processor upon starting to service the request. | |
550d787e | 380 | */ |
d4011df2 | 381 | @Override |
5419a136 AM |
382 | public void start() { |
383 | synchronized (this) { | |
384 | fRequestRunning = true; | |
385 | } | |
386 | handleStarted(); | |
387 | startedLatch.countDown(); | |
388 | } | |
389 | ||
390 | /** | |
391 | * Called by the request processor upon completion. | |
392 | */ | |
393 | @Override | |
394 | public void done() { | |
395 | synchronized (this) { | |
396 | if (!fRequestCompleted) { | |
397 | fRequestRunning = false; | |
398 | fRequestCompleted = true; | |
399 | } else { | |
400 | return; | |
401 | } | |
402 | } | |
403 | try { | |
404 | handleCompleted(); | |
405 | } finally { | |
406 | completedLatch.countDown(); | |
407 | } | |
408 | } | |
409 | ||
410 | /** | |
411 | * Called by the request processor upon failure. | |
412 | */ | |
413 | @Override | |
414 | public void fail() { | |
415 | synchronized (this) { | |
416 | fRequestFailed = true; | |
417 | } | |
418 | done(); | |
419 | } | |
420 | ||
421 | /** | |
422 | * Called by the request processor upon cancellation. | |
423 | */ | |
424 | @Override | |
425 | public void cancel() { | |
426 | synchronized (this) { | |
427 | fRequestCanceled = true; | |
428 | } | |
429 | done(); | |
8c8bf09f ASL |
430 | } |
431 | ||
cbd4ad82 FC |
432 | // ------------------------------------------------------------------------ |
433 | // Object | |
434 | // ------------------------------------------------------------------------ | |
435 | ||
436 | @Override | |
2fb2eb37 | 437 | // All requests have a unique id |
cbd4ad82 | 438 | public int hashCode() { |
12c155f5 | 439 | return getRequestId(); |
cbd4ad82 FC |
440 | } |
441 | ||
442 | @Override | |
443 | public boolean equals(Object other) { | |
6256d8ad AM |
444 | if (other instanceof TmfDataRequest) { |
445 | TmfDataRequest request = (TmfDataRequest) other; | |
5419a136 AM |
446 | return (request.fDataType == fDataType) && (request.fIndex == fIndex) |
447 | && (request.fNbRequested == fNbRequested); | |
12c155f5 FC |
448 | } |
449 | return false; | |
cbd4ad82 FC |
450 | } |
451 | ||
2fb2eb37 | 452 | @Override |
3b38ea61 | 453 | @SuppressWarnings("nls") |
2fb2eb37 | 454 | public String toString() { |
b1b156f3 PT |
455 | String name = getClass().getName(); |
456 | int dot = name.lastIndexOf('.'); | |
457 | if (dot >= 0) { | |
458 | name = name.substring(dot + 1); | |
459 | } | |
460 | return "[" + name + "(" + fRequestId + "," + fDataType.getSimpleName()+ "," + getExecType() | |
672a642a | 461 | + "," + fIndex + "," + fNbRequested + ")]"; |
2fb2eb37 | 462 | } |
8c8bf09f | 463 | } |