1 /*******************************************************************************
2 * Copyright (c) 2009, 2013 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 * Alexandre Montplaisir - Consolidated constructors
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.core
.request
;
16 import java
.util
.concurrent
.CountDownLatch
;
18 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.TmfCoreTracer
;
19 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
22 * TmfDataRequests are used to obtain blocks of contiguous data from a data
23 * provider. Open ranges can be used, especially for continuous streaming.
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.
31 * This data block approach is used to avoid busting the heap for very large
32 * trace files. The block size is configurable.
34 * The TmfProvider indicates that the request is completed by calling done().
35 * The request can be canceled at any time with cancel().
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
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.
72 * TODO: Implement request failures (codes, etc...)
75 * @author Francois Chouinard
77 public abstract class TmfDataRequest
implements ITmfDataRequest
{
79 // ------------------------------------------------------------------------
81 // ------------------------------------------------------------------------
83 /** The request count for all the events */
84 public static final int ALL_DATA
= Integer
.MAX_VALUE
;
86 private static int fRequestNumber
= 0;
88 // ------------------------------------------------------------------------
90 // ------------------------------------------------------------------------
92 private final Class
<?
extends ITmfEvent
> fDataType
;
93 private final ExecutionType fExecType
;
95 /** A unique request ID */
96 private final int fRequestId
;
98 /** The index (rank) of the requested event */
99 protected long fIndex
;
101 /** The number of requested events (ALL_DATA for all) */
102 protected int fNbRequested
;
104 /** The number of reads so far */
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
;
114 // ------------------------------------------------------------------------
116 // ------------------------------------------------------------------------
119 * Resets the request counter (used for testing)
121 public static void reset() {
126 * Request 'n' events of a given type from the given index (given priority).
127 * Events are returned in blocks of the given size.
130 * The requested data type.
132 * The index of the first event to retrieve. Use '0' to start at
133 * the beginning of the trace.
135 * The number of events requested. You can use
136 * {@link TmfDataRequest#ALL_DATA} to specify you want all events
139 * The requested execution priority.
141 public TmfDataRequest(Class
<?
extends ITmfEvent
> dataType
,
144 ExecutionType priority
) {
145 fRequestId
= fRequestNumber
++;
146 fDataType
= dataType
;
148 fNbRequested
= nbRequested
;
149 fExecType
= priority
;
152 fRequestRunning
= false;
153 fRequestCompleted
= false;
154 fRequestFailed
= false;
155 fRequestCanceled
= false;
157 if (!(this instanceof ITmfEventRequest
) && TmfCoreTracer
.isRequestTraced()) {
158 String type
= getClass().getName();
159 type
= type
.substring(type
.lastIndexOf('.') + 1);
160 @SuppressWarnings("nls")
161 String message
= "CREATED "
162 + (getExecType() == ITmfDataRequest
.ExecutionType
.BACKGROUND ?
"(BG)" : "(FG)")
163 + " Type=" + type
+ " Index=" + getIndex() + " NbReq=" + getNbRequested()
164 + " DataType=" + getDataType().getSimpleName();
165 TmfCoreTracer
.traceRequest(this, message
);
169 // ------------------------------------------------------------------------
171 // ------------------------------------------------------------------------
174 * @return the request ID
177 public int getRequestId() {
182 * @return the index of the first event requested
185 public long getIndex() {
190 * @return the execution type (priority)
193 public ExecutionType
getExecType() {
198 * @return the number of requested events (ALL_DATA = all)
201 public int getNbRequested() {
206 * @return the number of events read so far
209 public synchronized int getNbRead() {
214 * @return indicates if the request is currently running
217 public synchronized boolean isRunning() {
218 return fRequestRunning
;
222 * @return indicates if the request is completed
225 public synchronized boolean isCompleted() {
226 return fRequestCompleted
;
230 * @return indicates if the request has failed
233 public synchronized boolean isFailed() {
234 return fRequestFailed
;
238 * @return indicates if the request is canceled
241 public synchronized boolean isCancelled() {
242 return fRequestCanceled
;
246 * @return the requested data type
249 public Class
<?
extends ITmfEvent
> getDataType() {
253 // ------------------------------------------------------------------------
255 // ------------------------------------------------------------------------
258 * this method is called by the event provider to set the index corresponding to the time range start time
261 * the start time index
263 protected void setIndex(int index
) {
267 // ------------------------------------------------------------------------
269 // ------------------------------------------------------------------------
272 * Handle incoming data, one event at a time i.e. this method is invoked
273 * for every data item obtained by the request.
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.
284 * @param data a piece of data
287 public void handleData(ITmfEvent data
) {
294 public void handleStarted() {
295 if (TmfCoreTracer
.isRequestTraced()) {
296 TmfCoreTracer
.traceRequest(this, "STARTED"); //$NON-NLS-1$
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
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.
311 public void handleCompleted() {
312 boolean requestFailed
= false;
313 boolean requestCanceled
= false;
314 synchronized (this) {
315 requestFailed
= fRequestFailed
;
316 requestCanceled
= fRequestCanceled
;
321 } else if (requestCanceled
) {
326 if (TmfCoreTracer
.isRequestTraced()) {
327 TmfCoreTracer
.traceRequest(this, "COMPLETED (" + fNbRead
+ " events read)"); //$NON-NLS-1$ //$NON-NLS-2$
332 public void handleSuccess() {
333 if (TmfCoreTracer
.isRequestTraced()) {
334 TmfCoreTracer
.traceRequest(this, "SUCCEEDED"); //$NON-NLS-1$
339 public void handleFailure() {
340 if (TmfCoreTracer
.isRequestTraced()) {
341 TmfCoreTracer
.traceRequest(this, "FAILED"); //$NON-NLS-1$
346 public void handleCancel() {
347 if (TmfCoreTracer
.isRequestTraced()) {
348 TmfCoreTracer
.traceRequest(this, "CANCELLED"); //$NON-NLS-1$
353 * To suspend the client thread until the request starts (or is canceled).
355 * @throws InterruptedException
356 * If the thread was interrupted while waiting
358 public void waitForStart() throws InterruptedException
{
359 while (!fRequestRunning
) {
360 startedLatch
.await();
365 * To suspend the client thread until the request completes (or is
368 * @throws InterruptedException
369 * If the thread was interrupted while waiting
372 public void waitForCompletion() throws InterruptedException
{
373 while (!fRequestCompleted
) {
374 completedLatch
.await();
379 * Called by the request processor upon starting to service the request.
382 public void start() {
383 synchronized (this) {
384 fRequestRunning
= true;
387 startedLatch
.countDown();
391 * Called by the request processor upon completion.
395 synchronized (this) {
396 if (!fRequestCompleted
) {
397 fRequestRunning
= false;
398 fRequestCompleted
= true;
406 completedLatch
.countDown();
411 * Called by the request processor upon failure.
415 synchronized (this) {
416 fRequestFailed
= true;
422 * Called by the request processor upon cancellation.
425 public void cancel() {
426 synchronized (this) {
427 fRequestCanceled
= true;
432 // ------------------------------------------------------------------------
434 // ------------------------------------------------------------------------
437 // All requests have a unique id
438 public int hashCode() {
439 return getRequestId();
443 public boolean equals(Object other
) {
444 if (other
instanceof TmfDataRequest
) {
445 TmfDataRequest request
= (TmfDataRequest
) other
;
446 return (request
.fDataType
== fDataType
) && (request
.fIndex
== fIndex
)
447 && (request
.fNbRequested
== fNbRequested
);
453 @SuppressWarnings("nls")
454 public String
toString() {
455 return "[TmfDataRequest(" + fRequestId
+ "," + fDataType
.getSimpleName()
456 + "," + fIndex
+ "," + fNbRequested
+ ")]";