1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.request
;
15 import java
.util
.concurrent
.CountDownLatch
;
17 import org
.eclipse
.linuxtools
.tmf
.core
.Tracer
;
18 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
21 * <b><u>TmfDataRequest</u></b>
23 * TmfDataRequests are used to obtain blocks of contiguous data from a data provider. Open ranges can be used,
24 * especially for continuous streaming.
26 * The request is processed asynchronously by a TmfProvider and, as blocks of data become available, handleData() is
27 * invoked synchronously for each block. Upon return, the data instances go out of scope and become eligible for gc. It
28 * is is thus the responsibility of the requester to either clone or keep a reference to the data it wishes to track
31 * This data block approach is used to avoid busting the heap for very large trace files. The block size is
34 * The TmfProvider indicates that the request is completed by calling done(). The request can be canceled at any time
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) {
48 * public void handleSuccess() {
52 * public void handleFailure() {
56 * public void handleCancel() {
61 * fProcessor.process(request, true);
65 * TODO: Consider decoupling from "time range", "rank", etc and for the more generic notion of "criteria". This would
66 * allow to extend for "time range", etc instead of providing specialized constructors. This also means removing the
67 * criteria info from the data structure (with the possible exception of fNbRequested). The nice thing about it is that
68 * it would prepare us well for the coming generation of analysis tools.
70 * TODO: Implement request failures (codes, etc...)
72 public abstract class TmfDataRequest
<T
extends ITmfEvent
> implements ITmfDataRequest
<T
> {
74 // ------------------------------------------------------------------------
76 // ------------------------------------------------------------------------
78 // The default maximum number of events per chunk
79 public static final int DEFAULT_BLOCK_SIZE
= 1000;
81 // The request count for all the events
82 public static final int ALL_DATA
= Integer
.MAX_VALUE
;
84 private static int fRequestNumber
= 0;
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
90 private final Class
<T
> fDataType
;
91 private final ExecutionType fExecType
;
92 private final int fRequestId
; // A unique request ID
93 private int fIndex
; // The index (rank) of the requested event
94 private final int fNbRequested
; // The number of requested events (ALL_DATA for all)
95 private final int fBlockSize
; // The block size (for BG requests)
96 private int fNbRead
; // The number of reads so far
98 private CountDownLatch startedLatch
= new CountDownLatch(1);
99 private CountDownLatch completedLatch
= new CountDownLatch(1);
100 private boolean fRequestRunning
;
101 private boolean fRequestCompleted
;
102 private boolean fRequestFailed
;
103 private boolean fRequestCanceled
;
105 // ------------------------------------------------------------------------
107 // ------------------------------------------------------------------------
110 * Resets the request counter (used for testing)
112 public static void reset() {
117 * Request all the events of a given type (high priority)
118 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
120 * @param dataType the requested data type
122 public TmfDataRequest(Class
<T
> dataType
) {
123 this(dataType
, 0, ALL_DATA
, DEFAULT_BLOCK_SIZE
, ExecutionType
.FOREGROUND
);
127 * Request all the events of a given type (given priority)
128 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
130 * @param dataType the requested data type
131 * @param priority the requested execution priority
133 public TmfDataRequest(Class
<T
> dataType
, ExecutionType priority
) {
134 this(dataType
, 0, ALL_DATA
, DEFAULT_BLOCK_SIZE
, priority
);
138 * Request all the events of a given type from the given index (high priority)
139 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
141 * @param dataType the requested data type
142 * @param index the index of the first event to retrieve
144 public TmfDataRequest(Class
<T
> dataType
, int index
) {
145 this(dataType
, index
, ALL_DATA
, DEFAULT_BLOCK_SIZE
, ExecutionType
.FOREGROUND
);
149 * Request all the events of a given type from the given index (given priority)
150 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
152 * @param dataType the requested data type
153 * @param index the index of the first event to retrieve
154 * @param priority the requested execution priority
156 public TmfDataRequest(Class
<T
> dataType
, int index
, ExecutionType priority
) {
157 this(dataType
, index
, ALL_DATA
, DEFAULT_BLOCK_SIZE
, priority
);
161 * Request 'n' events of a given type from the given index (high priority)
162 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
164 * @param dataType the requested data type
165 * @param index the index of the first event to retrieve
166 * @param nbRequested the number of events requested
168 public TmfDataRequest(Class
<T
> dataType
, int index
, int nbRequested
) {
169 this(dataType
, index
, nbRequested
, DEFAULT_BLOCK_SIZE
, ExecutionType
.FOREGROUND
);
173 * Request 'n' events of a given type from the given index (given priority)
174 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
176 * @param dataType the requested data type
177 * @param index the index of the first event to retrieve
178 * @param nbRequested the number of events requested
179 * @param priority the requested execution priority
181 public TmfDataRequest(Class
<T
> dataType
, int index
, int nbRequested
, ExecutionType priority
) {
182 this(dataType
, index
, nbRequested
, DEFAULT_BLOCK_SIZE
, priority
);
186 * Request 'n' events of a given type from the given index (high priority).
187 * Events are returned in blocks of the given size.
189 * @param dataType the requested data type
190 * @param index the index of the first event to retrieve
191 * @param nbRequested the number of events requested
192 * @param blockSize the number of events per block
194 public TmfDataRequest(Class
<T
> dataType
, int index
, int nbRequested
, int blockSize
) {
195 this(dataType
, index
, nbRequested
, blockSize
, ExecutionType
.FOREGROUND
);
199 * Request 'n' events of a given type from the given index (given priority).
200 * Events are returned in blocks of the given size.
202 * @param dataType the requested data type
203 * @param index the index of the first event to retrieve
204 * @param nbRequested the number of events requested
205 * @param blockSize the number of events per block
206 * @param priority the requested execution priority
208 public TmfDataRequest(Class
<T
> dataType
, int index
, int nbRequested
, int blockSize
, ExecutionType priority
) {
209 fRequestId
= fRequestNumber
++;
210 fDataType
= dataType
;
212 fNbRequested
= nbRequested
;
213 fBlockSize
= blockSize
;
214 fExecType
= priority
;
217 fRequestRunning
= false;
218 fRequestCompleted
= false;
219 fRequestFailed
= false;
220 fRequestCanceled
= false;
222 if (Tracer
.isRequestTraced())
223 Tracer
.traceRequest(this, "created"); //$NON-NLS-1$
229 @SuppressWarnings("unused")
230 private TmfDataRequest(TmfDataRequest
<T
> other
) {
231 this(null, 0, ALL_DATA
, DEFAULT_BLOCK_SIZE
);
234 // ------------------------------------------------------------------------
236 // ------------------------------------------------------------------------
239 * @return the request ID
242 public int getRequestId() {
247 * @return the index of the first event requested
250 public int getIndex() {
255 * @return the execution type (priority)
258 public ExecutionType
getExecType() {
263 * @return the number of requested events (ALL_DATA = all)
266 public int getNbRequested() {
271 * @return the block size (for BG requests)
274 public int getBlockSize() {
279 * @return the number of events read so far
282 public synchronized int getNbRead() {
287 * @return indicates if the request is currently running
290 public synchronized boolean isRunning() {
291 return fRequestRunning
;
295 * @return indicates if the request is completed
298 public synchronized boolean isCompleted() {
299 return fRequestCompleted
;
303 * @return indicates if the request has failed
306 public synchronized boolean isFailed() {
307 return fRequestFailed
;
311 * @return indicates if the request is canceled
314 public synchronized boolean isCancelled() {
315 return fRequestCanceled
;
319 * @return the requested data type
322 public Class
<T
> getDataType() {
326 // ------------------------------------------------------------------------
328 // ------------------------------------------------------------------------
331 * this method is called by the event provider to set the index corresponding to the time range start time
334 * the start time index
336 protected void setIndex(int index
) {
340 // ------------------------------------------------------------------------
342 // ------------------------------------------------------------------------
345 * Handle incoming data, one event at a time i.e. this method is invoked
346 * for every data item obtained by the request.
348 * - Data items are received in the order they appear in the stream
349 * - Called by the request processor, in its execution thread, every time
350 * a block of data becomes available.
351 * - Request processor performs a synchronous call to handleData() i.e.
352 * its execution threads holds until handleData() returns.
353 * - Original data items are disposed of on return i.e. keep a reference
354 * (or a copy) if some persistence is needed between invocations.
355 * - When there is no more data, done() is called.
357 * @param data a piece of data
360 public void handleData(T data
) {
367 public void handleStarted() {
368 if (Tracer
.isRequestTraced())
369 Tracer
.traceRequest(this, "started"); //$NON-NLS-1$
373 * Handle the completion of the request. It is called when there is no
374 * more data available either because:
375 * - the request completed normally
376 * - the request failed
377 * - the request was canceled
379 * As a convenience, handleXXXX methods are provided. They are meant to be
380 * overridden by the application if it needs to handle these conditions.
383 public synchronized void handleCompleted() {
384 if (fRequestFailed
) {
386 } else if (fRequestCanceled
) {
391 if (Tracer
.isRequestTraced())
392 Tracer
.traceRequest(this, "completed (" + fNbRead
+ " events read)"); //$NON-NLS-1$ //$NON-NLS-2$
396 public void handleSuccess() {
397 if (Tracer
.isRequestTraced())
398 Tracer
.traceRequest(this, "succeeded"); //$NON-NLS-1$
402 public void handleFailure() {
403 if (Tracer
.isRequestTraced())
404 Tracer
.traceRequest(this, "failed"); //$NON-NLS-1$
408 public void handleCancel() {
409 if (Tracer
.isRequestTraced())
410 Tracer
.traceRequest(this, "cancelled"); //$NON-NLS-1$
414 * To suspend the client thread until the request starts (or is canceled).
416 * @throws InterruptedException
418 public void waitForStart() throws InterruptedException
{
419 while (!fRequestRunning
) {
420 startedLatch
.await();
425 * To suspend the client thread until the request completes (or is canceled).
427 * @throws InterruptedException
430 public void waitForCompletion() throws InterruptedException
{
431 while (!fRequestCompleted
) {
432 completedLatch
.await();
437 * Called by the request processor upon starting to service the request.
440 public void start() {
441 synchronized (this) {
442 fRequestRunning
= true;
445 startedLatch
.countDown();
449 * Called by the request processor upon completion.
453 synchronized (this) {
454 if (!fRequestCompleted
) {
455 fRequestRunning
= false;
456 fRequestCompleted
= true;
464 completedLatch
.countDown();
469 * Called by the request processor upon failure.
473 synchronized (this) {
474 fRequestFailed
= true;
480 * Called by the request processor upon cancellation.
483 public void cancel() {
484 synchronized (this) {
485 fRequestCanceled
= true;
490 // ------------------------------------------------------------------------
492 // ------------------------------------------------------------------------
495 // All requests have a unique id
496 public int hashCode() {
497 return getRequestId();
501 public boolean equals(Object other
) {
502 if (other
instanceof TmfDataRequest
<?
>) {
503 TmfDataRequest
<?
> request
= (TmfDataRequest
<?
>) other
;
504 return (request
.fDataType
== fDataType
) && (request
.fIndex
== fIndex
)
505 && (request
.fNbRequested
== fNbRequested
);
511 @SuppressWarnings("nls")
512 public String
toString() {
513 return "[TmfDataRequest(" + fRequestId
+ "," + fDataType
.getSimpleName() + "," + fIndex
+ "," + fNbRequested
514 + "," + getBlockSize() + ")]";