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
.internal
.tmf
.core
.TmfCoreTracer
;
18 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
21 * TmfDataRequests are used to obtain blocks of contiguous data from a data provider. Open ranges can be used,
22 * especially for continuous streaming.
24 * The request is processed asynchronously by a TmfProvider and, as blocks of data become available, handleData() is
25 * invoked synchronously for each block. Upon return, the data instances go out of scope and become eligible for gc. It
26 * is is thus the responsibility of the requester to either clone or keep a reference to the data it wishes to track
29 * This data block approach is used to avoid busting the heap for very large trace files. The block size is
32 * The TmfProvider indicates that the request is completed by calling done(). The request can be canceled at any time
38 * <code><i>TmfTimeWindow range = new TmfTimewindow(...);
39 * TmfDataRequest<DataType[]> request = new TmfDataRequest<DataType[]>(DataType.class, 0, NB_EVENTS, BLOCK_SIZE) {
40 * public void handleData() {
41 * DataType[] data = request.getData();
42 * for (DataType e : data) {
46 * public void handleSuccess() {
50 * public void handleFailure() {
54 * public void handleCancel() {
59 * fProcessor.process(request, true);
63 * TODO: Consider decoupling from "time range", "rank", etc and for the more generic notion of "criteria". This would
64 * allow to extend for "time range", etc instead of providing specialized constructors. This also means removing the
65 * criteria info from the data structure (with the possible exception of fNbRequested). The nice thing about it is that
66 * it would prepare us well for the coming generation of analysis tools.
68 * TODO: Implement request failures (codes, etc...)
71 * @author Francois Chouinard
73 public abstract class TmfDataRequest
implements ITmfDataRequest
{
75 // ------------------------------------------------------------------------
77 // ------------------------------------------------------------------------
79 /** The default maximum number of events per chunk */
80 public static final int DEFAULT_BLOCK_SIZE
= 1000;
82 /** The request count for all the events */
83 public static final int ALL_DATA
= Integer
.MAX_VALUE
;
85 private static int fRequestNumber
= 0;
87 // ------------------------------------------------------------------------
89 // ------------------------------------------------------------------------
91 private final Class
<?
extends ITmfEvent
> fDataType
;
92 private final ExecutionType fExecType
;
94 /** A unique request ID */
95 private final int fRequestId
;
97 /** The index (rank) of the requested event */
98 protected long fIndex
;
100 /** The number of requested events (ALL_DATA for all) */
101 protected int fNbRequested
;
103 /** The block size (for BG requests) */
104 private final int fBlockSize
;
106 /** The number of reads so far */
109 private final CountDownLatch startedLatch
= new CountDownLatch(1);
110 private final CountDownLatch completedLatch
= new CountDownLatch(1);
111 private boolean fRequestRunning
;
112 private boolean fRequestCompleted
;
113 private boolean fRequestFailed
;
114 private boolean fRequestCanceled
;
116 // ------------------------------------------------------------------------
118 // ------------------------------------------------------------------------
121 * Resets the request counter (used for testing)
123 public static void reset() {
128 * Request all the events of a given type (high priority)
129 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
131 * @param dataType the requested data type
133 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
) {
134 this(dataType
, 0, ALL_DATA
, DEFAULT_BLOCK_SIZE
, ExecutionType
.FOREGROUND
);
138 * Request all the events of a given type (given priority)
139 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
141 * @param dataType the requested data type
142 * @param priority the requested execution priority
144 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, ExecutionType priority
) {
145 this(dataType
, 0, ALL_DATA
, DEFAULT_BLOCK_SIZE
, priority
);
149 * Request all the events of a given type from the given index (high 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
155 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, long index
) {
156 this(dataType
, index
, ALL_DATA
, DEFAULT_BLOCK_SIZE
, ExecutionType
.FOREGROUND
);
160 * Request all the events of a given type from the given index (given priority)
161 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
163 * @param dataType the requested data type
164 * @param index the index of the first event to retrieve
165 * @param priority the requested execution priority
167 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, long index
, ExecutionType priority
) {
168 this(dataType
, index
, ALL_DATA
, DEFAULT_BLOCK_SIZE
, priority
);
172 * Request 'n' events of a given type from the given index (high priority)
173 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
175 * @param dataType the requested data type
176 * @param index the index of the first event to retrieve
177 * @param nbRequested the number of events requested
179 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, long index
, int nbRequested
) {
180 this(dataType
, index
, nbRequested
, DEFAULT_BLOCK_SIZE
, ExecutionType
.FOREGROUND
);
184 * Request 'n' events of a given type from the given index (given priority)
185 * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
187 * @param dataType the requested data type
188 * @param index the index of the first event to retrieve
189 * @param nbRequested the number of events requested
190 * @param priority the requested execution priority
192 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, long index
, int nbRequested
, ExecutionType priority
) {
193 this(dataType
, index
, nbRequested
, DEFAULT_BLOCK_SIZE
, priority
);
197 * Request 'n' events of a given type from the given index (high priority).
198 * Events are returned in blocks of the given size.
200 * @param dataType the requested data type
201 * @param index the index of the first event to retrieve
202 * @param nbRequested the number of events requested
203 * @param blockSize the number of events per block
205 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, long index
, int nbRequested
, int blockSize
) {
206 this(dataType
, index
, nbRequested
, blockSize
, ExecutionType
.FOREGROUND
);
210 * Request 'n' events of a given type from the given index (given priority).
211 * Events are returned in blocks of the given size.
213 * @param dataType the requested data type
214 * @param index the index of the first event to retrieve
215 * @param nbRequested the number of events requested
216 * @param blockSize the number of events per block
217 * @param priority the requested execution priority
219 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
, long index
, int nbRequested
, int blockSize
, ExecutionType priority
) {
220 fRequestId
= fRequestNumber
++;
221 fDataType
= dataType
;
223 fNbRequested
= nbRequested
;
224 fBlockSize
= blockSize
;
225 fExecType
= priority
;
228 fRequestRunning
= false;
229 fRequestCompleted
= false;
230 fRequestFailed
= false;
231 fRequestCanceled
= false;
233 if (!(this instanceof ITmfEventRequest
) && TmfCoreTracer
.isRequestTraced()) {
234 String type
= getClass().getName();
235 type
= type
.substring(type
.lastIndexOf('.') + 1);
236 @SuppressWarnings("nls")
237 String message
= "CREATED "
238 + (getExecType() == ITmfDataRequest
.ExecutionType
.BACKGROUND ?
"(BG)" : "(FG)")
239 + " Type=" + type
+ " Index=" + getIndex() + " NbReq=" + getNbRequested()
240 + " DataType=" + getDataType().getSimpleName();
241 TmfCoreTracer
.traceRequest(this, message
);
248 @SuppressWarnings("unused")
249 private TmfDataRequest(TmfDataRequest other
) {
250 this(null, 0, ALL_DATA
, DEFAULT_BLOCK_SIZE
);
253 // ------------------------------------------------------------------------
255 // ------------------------------------------------------------------------
258 * @return the request ID
261 public int getRequestId() {
266 * @return the index of the first event requested
269 public long getIndex() {
274 * @return the execution type (priority)
277 public ExecutionType
getExecType() {
282 * @return the number of requested events (ALL_DATA = all)
285 public int getNbRequested() {
290 * @return the block size (for BG requests)
293 public int getBlockSize() {
298 * @return the number of events read so far
301 public synchronized int getNbRead() {
306 * @return indicates if the request is currently running
309 public synchronized boolean isRunning() {
310 return fRequestRunning
;
314 * @return indicates if the request is completed
317 public synchronized boolean isCompleted() {
318 return fRequestCompleted
;
322 * @return indicates if the request has failed
325 public synchronized boolean isFailed() {
326 return fRequestFailed
;
330 * @return indicates if the request is canceled
333 public synchronized boolean isCancelled() {
334 return fRequestCanceled
;
338 * @return the requested data type
341 public Class
<?
extends ITmfEvent
> getDataType() {
345 // ------------------------------------------------------------------------
347 // ------------------------------------------------------------------------
350 * this method is called by the event provider to set the index corresponding to the time range start time
353 * the start time index
355 protected void setIndex(int index
) {
359 // ------------------------------------------------------------------------
361 // ------------------------------------------------------------------------
364 * Handle incoming data, one event at a time i.e. this method is invoked
365 * for every data item obtained by the request.
367 * - Data items are received in the order they appear in the stream
368 * - Called by the request processor, in its execution thread, every time
369 * a block of data becomes available.
370 * - Request processor performs a synchronous call to handleData() i.e.
371 * its execution threads holds until handleData() returns.
372 * - Original data items are disposed of on return i.e. keep a reference
373 * (or a copy) if some persistence is needed between invocations.
374 * - When there is no more data, done() is called.
376 * @param data a piece of data
379 public void handleData(ITmfEvent data
) {
386 public void handleStarted() {
387 if (TmfCoreTracer
.isRequestTraced()) {
388 TmfCoreTracer
.traceRequest(this, "STARTED"); //$NON-NLS-1$
393 * Handle the completion of the request. It is called when there is no
394 * more data available either because:
395 * - the request completed normally
396 * - the request failed
397 * - the request was canceled
399 * As a convenience, handleXXXX methods are provided. They are meant to be
400 * overridden by the application if it needs to handle these conditions.
403 public void handleCompleted() {
404 boolean requestFailed
= false;
405 boolean requestCanceled
= false;
406 synchronized (this) {
407 requestFailed
= fRequestFailed
;
408 requestCanceled
= fRequestCanceled
;
413 } else if (requestCanceled
) {
418 if (TmfCoreTracer
.isRequestTraced()) {
419 TmfCoreTracer
.traceRequest(this, "COMPLETED (" + fNbRead
+ " events read)"); //$NON-NLS-1$ //$NON-NLS-2$
424 public void handleSuccess() {
425 if (TmfCoreTracer
.isRequestTraced()) {
426 TmfCoreTracer
.traceRequest(this, "SUCCEEDED"); //$NON-NLS-1$
431 public void handleFailure() {
432 if (TmfCoreTracer
.isRequestTraced()) {
433 TmfCoreTracer
.traceRequest(this, "FAILED"); //$NON-NLS-1$
438 public void handleCancel() {
439 if (TmfCoreTracer
.isRequestTraced()) {
440 TmfCoreTracer
.traceRequest(this, "CANCELLED"); //$NON-NLS-1$
445 * To suspend the client thread until the request starts (or is canceled).
447 * @throws InterruptedException
448 * If the thread was interrupted while waiting
450 public void waitForStart() throws InterruptedException
{
451 while (!fRequestRunning
) {
452 startedLatch
.await();
457 * To suspend the client thread until the request completes (or is
460 * @throws InterruptedException
461 * If the thread was interrupted while waiting
464 public void waitForCompletion() throws InterruptedException
{
465 while (!fRequestCompleted
) {
466 completedLatch
.await();
471 * Called by the request processor upon starting to service the request.
474 public void start() {
475 synchronized (this) {
476 fRequestRunning
= true;
479 startedLatch
.countDown();
483 * Called by the request processor upon completion.
487 synchronized (this) {
488 if (!fRequestCompleted
) {
489 fRequestRunning
= false;
490 fRequestCompleted
= true;
498 completedLatch
.countDown();
503 * Called by the request processor upon failure.
507 synchronized (this) {
508 fRequestFailed
= true;
514 * Called by the request processor upon cancellation.
517 public void cancel() {
518 synchronized (this) {
519 fRequestCanceled
= true;
524 // ------------------------------------------------------------------------
526 // ------------------------------------------------------------------------
529 // All requests have a unique id
530 public int hashCode() {
531 return getRequestId();
535 public boolean equals(Object other
) {
536 if (other
instanceof TmfDataRequest
) {
537 TmfDataRequest request
= (TmfDataRequest
) other
;
538 return (request
.fDataType
== fDataType
) && (request
.fIndex
== fIndex
)
539 && (request
.fNbRequested
== fNbRequested
);
545 @SuppressWarnings("nls")
546 public String
toString() {
547 return "[TmfDataRequest(" + fRequestId
+ "," + fDataType
.getSimpleName() + "," + fIndex
+ "," + fNbRequested
548 + "," + getBlockSize() + ")]";