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