560c4431516b437880b82e7937b51b8333317407
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / request / TmfDataRequest.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 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.request;
14
15 import org.eclipse.linuxtools.tmf.Tracer;
16 import org.eclipse.linuxtools.tmf.event.TmfData;
17
18 /**
19 * <b><u>TmfDataRequest</u></b>
20 * <p>
21 * TmfDataRequests are used to obtain blocks of contiguous data from a data
22 * provider. Open ranges can be used, especially for continuous streaming.
23 * <p>
24 * The request is processed asynchronously by a TmfProvider and, as blocks
25 * of data become available, handleData() is invoked synchronously for each
26 * block. Upon return, the data instances go out of scope and become eligible
27 * for gc. It is is thus the responsibility of the requester to either clone
28 * or keep a reference to the data it wishes to track specifically.
29 * <p>
30 * This data block approach is used to avoid busting the heap for very
31 * large trace files. The block size is configurable.
32 * <p>
33 * The TmfProvider indicates that the request is completed by calling done().
34 * The request can be canceled at any time with cancel().
35 * <p>
36 * Typical usage:
37 *<pre><code><i>TmfTimeWindow range = new TmfTimewindow(...);
38 *TmfDataRequest&lt;DataType[]&gt; request = new TmfDataRequest&lt;DataType[]&gt;(DataType.class, 0, NB_EVENTS, BLOCK_SIZE) {
39 * public void handleData() {
40 * DataType[] data = request.getData();
41 * for (DataType e : data) {
42 * // do something
43 * }
44 * }
45 * public void handleSuccess() {
46 * // do something
47 * }
48 * }
49 * public void handleFailure() {
50 * // do something
51 * }
52 * }
53 * public void handleCancel() {
54 * // do something
55 * }
56 * }
57 *};
58 *fProcessor.process(request, true);
59 *</i></code></pre>
60 *
61 * TODO: Consider decoupling from "time range", "rank", etc and for the more
62 * generic notion of "criteria". This would allow to extend for "time range", etc
63 * instead of providing specialized constructors. This also means removing the
64 * criteria info from the data structure (with the possible exception of fNbRequested).
65 * The nice thing about it is that it would prepare us well for the coming generation
66 * of analysis tools.
67 *
68 * TODO: Implement request failures (codes, etc...)
69 */
70 public abstract class TmfDataRequest<T extends TmfData> implements ITmfDataRequest<T> {
71
72 // ------------------------------------------------------------------------
73 // Constants
74 // ------------------------------------------------------------------------
75
76 // The default maximum number of events per chunk
77 public static final int DEFAULT_BLOCK_SIZE = 1000;
78
79 // The request count for all the events
80 public static final int ALL_DATA = Integer.MAX_VALUE;
81
82 private static int fRequestNumber = 0;
83
84 // ------------------------------------------------------------------------
85 // Attributes
86 // ------------------------------------------------------------------------
87
88 private final Class<T> fDataType;
89 private final int fRequestId; // A unique request ID
90 private final int fIndex; // The index (rank) of the requested event
91 private final int fNbRequested; // The number of requested events (ALL_DATA for all)
92 private final int fBlockSize; // The maximum number of events per chunk
93 private int fNbRead; // The number of reads so far
94
95 private final Object lock;
96 private boolean fRequestRunning = false;
97 private boolean fRequestCompleted = false;
98 private boolean fRequestFailed = false;
99 private boolean fRequestCanceled = false;
100
101 private T[] fData; // Data object
102
103 // ------------------------------------------------------------------------
104 // Constructors
105 // ------------------------------------------------------------------------
106
107 /**
108 * Resets the request counter (used for testing)
109 */
110 public static void reset() {
111 fRequestNumber = 0;
112 }
113
114 /**
115 * Default constructor
116 *
117 * @param dataType the requested data type
118 */
119 public TmfDataRequest(Class<T> dataType) {
120 this(dataType, 0, ALL_DATA, DEFAULT_BLOCK_SIZE);
121 }
122
123 /**
124 * @param dataType the requested data type
125 * @param nbRequested the number of data items requested
126 */
127 public TmfDataRequest(Class<T> dataType, int index) {
128 this(dataType, index, ALL_DATA, DEFAULT_BLOCK_SIZE);
129 }
130
131 /**
132 * @param dataType the requested data type
133 * @param index the index (rank) of the first event requested
134 * @param blockSize the number of data items per block
135 */
136 public TmfDataRequest(Class<T> dataType, int index, int nbRequested) {
137 this(dataType, index, nbRequested, DEFAULT_BLOCK_SIZE);
138 }
139
140 /**
141 * @param dataType the requested data type
142 * @param index the index (rank) of the first event requested
143 * @param nbRequested the number of data items requested
144 * @param blockSize the number of data items per block
145 */
146 public TmfDataRequest(Class<T> dataType, int index, int nbRequested, int blockSize) {
147 fRequestId = fRequestNumber++;
148 fDataType = dataType;
149 fIndex = index;
150 fNbRequested = nbRequested;
151 fBlockSize = blockSize;
152 fNbRead = 0;
153 lock = new Object();
154 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "created");
155 }
156
157 /**
158 * Copy constructor
159 */
160 @SuppressWarnings("unused")
161 private TmfDataRequest(TmfDataRequest<T> other) {
162 this(null, 0, ALL_DATA, DEFAULT_BLOCK_SIZE);
163 }
164
165 // ------------------------------------------------------------------------
166 // Accessors
167 // ------------------------------------------------------------------------
168
169 /**
170 * @return the request ID
171 */
172 public int getRequestId() {
173 return fRequestId;
174 }
175
176 /**
177 * @return the index of the first event requested
178 */
179 public int getIndex() {
180 return fIndex;
181 }
182
183 /**
184 * @return the number of requested events (ALL_DATA = all)
185 */
186 public int getNbRequested() {
187 return fNbRequested;
188 }
189
190 /**
191 * @return the block size
192 */
193 public int getBlockize() {
194 return fBlockSize;
195 }
196
197 /**
198 * @return the number of events read so far
199 */
200 public synchronized int getNbRead() {
201 return fNbRead;
202 }
203
204 /**
205 * @return indicates if the request is completed
206 */
207 public boolean isRunning() {
208 return fRequestRunning;
209 }
210
211 /**
212 * @return indicates if the request is completed
213 */
214 public boolean isCompleted() {
215 return fRequestCompleted;
216 }
217
218 /**
219 * @return indicates if the request is canceled
220 */
221 public boolean isFailed() {
222 return fRequestFailed;
223 }
224
225 /**
226 * @return indicates if the request is canceled
227 */
228 public boolean isCancelled() {
229 return fRequestCanceled;
230 }
231
232 /**
233 * @return the requested data type
234 */
235 public Class<T> getDataType() {
236 return fDataType;
237 }
238
239 // ------------------------------------------------------------------------
240 // Operators
241 // ------------------------------------------------------------------------
242
243 /**
244 * Sets the data object to specified value. To be called by the
245 * asynchronous method implementor.
246 * @param data Data value to set.
247 */
248 public synchronized void setData(T[] data) {
249 fNbRead += data.length;
250 fData = data;
251 }
252
253 /**
254 * Returns the data value, null if not set.
255 */
256 public synchronized T[] getData() {
257 return fData;
258 }
259
260 /**
261 * Handle a block of incoming data. This method is called every time
262 * a block of data becomes available.
263 *
264 * - Data items are received in the order they appear in the stream.
265 * - Called by the request processor, in its execution thread, every time a
266 * block of data becomes available.
267 * - Request processor performs a synchronous call to handlePartialResult()
268 * i.e. its execution threads holds until handlePartialData() returns.
269 * - Original data items are disposed of on return i.e. keep a reference
270 * (or a copy) if some persistence is needed between invocations.
271 * - When there is no more data, done() is called.
272 *
273 * @param events - an array of events
274 */
275 public abstract void handleData();
276
277 public void handleStarted() {
278 }
279
280 /**
281 * Handle the completion of the request. It is called when there is no more
282 * data available either because:
283 * - the request completed normally
284 * - the request failed
285 * - the request was canceled
286 *
287 * As a convenience, handleXXXX methods are provided. They are meant to be
288 * overridden by the application if it needs to handle these conditions.
289 */
290 public void handleCompleted() {
291 if (fRequestFailed) {
292 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "failed");
293 handleFailure();
294 }
295 else if (fRequestCanceled) {
296 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "cancelled");
297 handleCancel();
298 }
299 else {
300 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "succeeded");
301 handleSuccess();
302 }
303 }
304
305 public void handleSuccess() {
306 }
307
308 public void handleFailure() {
309 }
310
311 public void handleCancel() {
312 }
313
314 /**
315 * To suspend the client thread until the request completes (or is
316 * canceled).
317 *
318 * @throws InterruptedException
319 */
320 public void waitForCompletion() throws InterruptedException {
321 synchronized (lock) {
322 while (!fRequestCompleted)
323 lock.wait();
324 }
325 }
326
327 /**
328 * Called by the request processor upon starting to service the request.
329 */
330 public void start() {
331 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "starting");
332 synchronized(lock) {
333 fRequestRunning = true;
334 lock.notify();
335 }
336 handleStarted();
337 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "started");
338 }
339
340 /**
341 * Called by the request processor upon completion.
342 */
343 public void done() {
344 if (Tracer.isRequestTraced()) Tracer.traceRequest(this, "completing");
345 synchronized(lock) {
346 fRequestRunning = false;
347 fRequestCompleted = true;
348 lock.notify();
349 }
350 handleCompleted();
351 }
352
353 /**
354 * Called by the request processor upon failure.
355 */
356 public void fail() {
357 synchronized(lock) {
358 fRequestFailed = true;
359 done();
360 }
361 }
362
363 /**
364 * Called by the request processor upon cancellation.
365 */
366 public void cancel() {
367 synchronized(lock) {
368 fRequestCanceled = true;
369 done();
370 }
371 }
372
373 // ------------------------------------------------------------------------
374 // Object
375 // ------------------------------------------------------------------------
376
377 @Override
378 // All requests have a unique id
379 public int hashCode() {
380 return getRequestId();
381 }
382
383 @Override
384 public boolean equals(Object other) {
385 if (other instanceof TmfDataRequest<?>) {
386 TmfDataRequest<?> request = (TmfDataRequest<?>) other;
387 return (request.fDataType == fDataType) &&
388 (request.fIndex == fIndex) &&
389 (request.fNbRequested == fNbRequested);
390 }
391 return false;
392 }
393
394 @Override
395 public String toString() {
396 return "[TmfDataRequest(" + fRequestId + "," + fDataType.getSimpleName()
397 + "," + fIndex + "," + fNbRequested + "," + fBlockSize + ")]";
398 }
399
400 }
This page took 0.039193 seconds and 4 git commands to generate.