tmf: Fix regression in event requests
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / request / TmfDataRequest.java
index 7161871e229eb442008122880c493738affe83d8..025657ab0d1d66d8bd55ddf282df10d893f976f8 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2010, 2012 Ericsson
+ * Copyright (c) 2009, 2010 Ericsson
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -8,30 +8,29 @@
  *
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
- *   Francois Chouinard - Rebased on TmfRequest and deprecated
  *******************************************************************************/
 
 package org.eclipse.linuxtools.tmf.core.request;
 
+import java.util.concurrent.CountDownLatch;
+
 import org.eclipse.linuxtools.internal.tmf.core.TmfCoreTracer;
 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
 
 /**
- * TmfDataRequests are used to obtain blocks of contiguous data from a data
- * provider. Open ranges can be used, especially for continuous streaming.
+ * TmfDataRequests are used to obtain blocks of contiguous data from a data provider. Open ranges can be used,
+ * especially for continuous streaming.
  * <p>
- * The request is processed asynchronously by a TmfProvider and, as blocks of
- * data become available, handleData() is invoked synchronously for each block.
- * Upon return, the data instances go out of scope and become eligible for gc.
- * It is is thus the responsibility of the requester to either clone or keep a
- * reference to the data it wishes to track specifically.
+ * The request is processed asynchronously by a TmfProvider and, as blocks of data become available, handleData() is
+ * invoked synchronously for each block. Upon return, the data instances go out of scope and become eligible for gc. It
+ * is is thus the responsibility of the requester to either clone or keep a reference to the data it wishes to track
+ * specifically.
  * <p>
- * This data block approach is used to avoid busting the heap for very large
- * trace files. The block size is configurable.
+ * This data block approach is used to avoid busting the heap for very large trace files. The block size is
+ * configurable.
  * <p>
- * The TmfProvider indicates that the request is completed by calling done().
- * The request can be canceled at any time with cancel().
+ * The TmfProvider indicates that the request is completed by calling done(). The request can be canceled at any time
+ * with cancel().
  * <p>
  * Typical usage:
  *
@@ -61,21 +60,17 @@ import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
  * </i></code>
  * </pre>
  *
- * TODO: Consider decoupling from "time range", "rank", etc and for the more
- * generic notion of "criteria". This would allow to extend for "time range",
- * etc instead of providing specialized constructors. This also means removing
- * the criteria info from the data structure (with the possible exception of
- * fNbRequested). The nice thing about it is that it would prepare us well for
- * the coming generation of analysis tools.
+ * TODO: Consider decoupling from "time range", "rank", etc and for the more generic notion of "criteria". This would
+ * allow to extend for "time range", etc instead of providing specialized constructors. This also means removing the
+ * criteria info from the data structure (with the possible exception of fNbRequested). The nice thing about it is that
+ * it would prepare us well for the coming generation of analysis tools.
  *
  * TODO: Implement request failures (codes, etc...)
  *
+ * @version 1.0
  * @author Francois Chouinard
- * @version 1.1
  */
-@Deprecated
-@SuppressWarnings("deprecation")
-public abstract class TmfDataRequest extends TmfRequest implements ITmfDataRequest {
+public abstract class TmfDataRequest implements ITmfDataRequest {
 
     // ------------------------------------------------------------------------
     // Constants
@@ -87,19 +82,48 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
     /** The request count for all the events */
     public static final int ALL_DATA = Integer.MAX_VALUE;
 
+    private static int fRequestNumber = 0;
+
     // ------------------------------------------------------------------------
     // Attributes
     // ------------------------------------------------------------------------
 
-    private final TmfEventTypeFilter fEventTypeFilter;
+    private final Class<? extends ITmfEvent> fDataType;
+    private final ExecutionType fExecType;
+
+    /** A unique request ID */
+    private final int fRequestId;
+
+    /** The index (rank) of the requested event */
+    protected long fIndex;
+
+    /** The number of requested events (ALL_DATA for all) */
+    protected int fNbRequested;
 
     /** The block size (for BG requests) */
     private final int fBlockSize;
 
+    /** The number of reads so far */
+    private int fNbRead;
+
+    private final CountDownLatch startedLatch = new CountDownLatch(1);
+    private final CountDownLatch completedLatch = new CountDownLatch(1);
+    private boolean fRequestRunning;
+    private boolean fRequestCompleted;
+    private boolean fRequestFailed;
+    private boolean fRequestCanceled;
+
     // ------------------------------------------------------------------------
     // Constructors
     // ------------------------------------------------------------------------
 
+    /**
+     * Resets the request counter (used for testing)
+     */
+    public static void reset() {
+        fRequestNumber = 0;
+    }
+
     /**
      * Request all the events of a given type (high priority)
      * Events are returned in blocks of the default size (DEFAULT_BLOCK_SIZE).
@@ -193,12 +217,18 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
      * @param priority the requested execution priority
      */
     public TmfDataRequest(Class<? extends ITmfEvent> dataType, long index, int nbRequested, int blockSize, ExecutionType priority) {
-        super(TmfTimeRange.ETERNITY, index, nbRequested,
-              priority == ITmfDataRequest.ExecutionType.FOREGROUND ? ITmfRequest.TmfRequestPriority.HIGH : ITmfRequest.TmfRequestPriority.NORMAL);
-        fEventTypeFilter = new TmfEventTypeFilter(dataType);
-        addEventFilter(fEventTypeFilter);
-
+        fRequestId = fRequestNumber++;
+        fDataType = dataType;
+        fIndex = index;
+        fNbRequested = nbRequested;
         fBlockSize = blockSize;
+        fExecType = priority;
+        fNbRead = 0;
+
+        fRequestRunning = false;
+        fRequestCompleted = false;
+        fRequestFailed = false;
+        fRequestCanceled = false;
 
         if (!(this instanceof ITmfEventRequest) && TmfCoreTracer.isRequestTraced()) {
             String type = getClass().getName();
@@ -224,12 +254,20 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
     // Accessors
     // ------------------------------------------------------------------------
 
+    /**
+     * @return the request ID
+     */
+    @Override
+    public int getRequestId() {
+        return fRequestId;
+    }
+
     /**
      * @return the index of the first event requested
      */
     @Override
     public long getIndex() {
-        return getStartIndex();
+        return fIndex;
     }
 
     /**
@@ -237,17 +275,15 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
      */
     @Override
     public ExecutionType getExecType() {
-        return getRequestPriority() == ITmfRequest.TmfRequestPriority.HIGH ?
-                ITmfDataRequest.ExecutionType.FOREGROUND : ITmfDataRequest.ExecutionType.BACKGROUND;
+        return fExecType;
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.linuxtools.tmf.core.request.ITmfRequest#getNbRequested()
+    /**
+     * @return the number of requested events (ALL_DATA = all)
      */
     @Override
-    public synchronized long getNbRequested() {
-        long nbRequested = super.getNbRequested();
-        return (nbRequested > 0 && nbRequested < Integer.MAX_VALUE) ? nbRequested : Integer.MAX_VALUE;
+    public int getNbRequested() {
+        return fNbRequested;
     }
 
     /**
@@ -263,7 +299,39 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
      */
     @Override
     public synchronized int getNbRead() {
-        return (int) getNbEventsRead();
+        return fNbRead;
+    }
+
+    /**
+     * @return indicates if the request is currently running
+     */
+    @Override
+    public synchronized boolean isRunning() {
+        return fRequestRunning;
+    }
+
+    /**
+     * @return indicates if the request is completed
+     */
+    @Override
+    public synchronized boolean isCompleted() {
+        return fRequestCompleted;
+    }
+
+    /**
+     * @return indicates if the request has failed
+     */
+    @Override
+    public synchronized boolean isFailed() {
+        return fRequestFailed;
+    }
+
+    /**
+     * @return indicates if the request is canceled
+     */
+    @Override
+    public synchronized boolean isCancelled() {
+        return fRequestCanceled;
     }
 
     /**
@@ -271,7 +339,7 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
      */
     @Override
     public Class<? extends ITmfEvent> getDataType() {
-        return fEventTypeFilter.getEventType();
+        return fDataType;
     }
 
     // ------------------------------------------------------------------------
@@ -285,11 +353,11 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
      *            the start time index
      */
     protected void setIndex(int index) {
-        setStartIndex(index);
+        fIndex = index;
     }
 
     // ------------------------------------------------------------------------
-    // Operations
+    // Operators
     // ------------------------------------------------------------------------
 
     /**
@@ -309,18 +377,148 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
      */
     @Override
     public void handleData(ITmfEvent data) {
-        super.handleEvent(data);
+        if (data != null) {
+            fNbRead++;
+        }
+    }
+
+    @Override
+    public void handleStarted() {
+        if (TmfCoreTracer.isRequestTraced()) {
+            TmfCoreTracer.traceRequest(this, "STARTED"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Handle the completion of the request. It is called when there is no
+     * more data available either because:
+     * - the request completed normally
+     * - the request failed
+     * - the request was canceled
+     *
+     * As a convenience, handleXXXX methods are provided. They are meant to be
+     * overridden by the application if it needs to handle these conditions.
+     */
+    @Override
+    public void handleCompleted() {
+        boolean requestFailed = false;
+        boolean requestCanceled = false;
+        synchronized (this) {
+            requestFailed = fRequestFailed;
+            requestCanceled = fRequestCanceled;
+        }
+
+        if (requestFailed) {
+            handleFailure();
+        } else if (requestCanceled) {
+            handleCancel();
+        } else {
+            handleSuccess();
+        }
+        if (TmfCoreTracer.isRequestTraced()) {
+            TmfCoreTracer.traceRequest(this, "COMPLETED (" + fNbRead + " events read)"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#handleEvent(org.eclipse.linuxtools.tmf.core.event.ITmfEvent)
+    @Override
+    public void handleSuccess() {
+        if (TmfCoreTracer.isRequestTraced()) {
+            TmfCoreTracer.traceRequest(this, "SUCCEEDED"); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public void handleFailure() {
+        if (TmfCoreTracer.isRequestTraced()) {
+            TmfCoreTracer.traceRequest(this, "FAILED"); //$NON-NLS-1$
+        }
+    }
+
+    @Override
+    public void handleCancel() {
+        if (TmfCoreTracer.isRequestTraced()) {
+            TmfCoreTracer.traceRequest(this, "CANCELLED"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * To suspend the client thread until the request starts (or is canceled).
+     *
+     * @throws InterruptedException
+     *             If the thread was interrupted while waiting
+     */
+    public void waitForStart() throws InterruptedException {
+        while (!fRequestRunning) {
+            startedLatch.await();
+        }
+    }
+
+    /**
+     * To suspend the client thread until the request completes (or is
+     * canceled).
      *
-     * The TmfEventThread now calls handleEvent(). To ensure that handleData()
-     * overrides are correctly handled, the method is overridden here.
+     * @throws InterruptedException
+     *             If the thread was interrupted while waiting
+     */
+    @Override
+    public void waitForCompletion() throws InterruptedException {
+        while (!fRequestCompleted) {
+            completedLatch.await();
+        }
+    }
+
+    /**
+     * Called by the request processor upon starting to service the request.
      */
     @Override
-    public synchronized void handleEvent(ITmfEvent data) {
-        handleData(data);
+    public void start() {
+        synchronized (this) {
+            fRequestRunning = true;
+        }
+        handleStarted();
+        startedLatch.countDown();
+    }
+
+    /**
+     * Called by the request processor upon completion.
+     */
+    @Override
+    public void done() {
+        synchronized (this) {
+            if (!fRequestCompleted) {
+                fRequestRunning = false;
+                fRequestCompleted = true;
+            } else {
+                return;
+            }
+        }
+        try {
+            handleCompleted();
+        } finally {
+            completedLatch.countDown();
+        }
+    }
+
+    /**
+     * Called by the request processor upon failure.
+     */
+    @Override
+    public void fail() {
+        synchronized (this) {
+            fRequestFailed = true;
+        }
+        done();
+    }
+
+    /**
+     * Called by the request processor upon cancellation.
+     */
+    @Override
+    public void cancel() {
+        synchronized (this) {
+            fRequestCanceled = true;
+        }
+        done();
     }
 
     // ------------------------------------------------------------------------
@@ -335,13 +533,10 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
 
     @Override
     public boolean equals(Object other) {
-        if (other == this) {
-            return true;
-        }
         if (other instanceof TmfDataRequest) {
             TmfDataRequest request = (TmfDataRequest) other;
-            return (request.fEventTypeFilter.getEventType() == fEventTypeFilter.getEventType()) && (request.getStartIndex() == getStartIndex())
-                    && (request.getNbRequested() == getNbRequested());
+            return (request.fDataType == fDataType) && (request.fIndex == fIndex)
+                    && (request.fNbRequested == fNbRequested);
         }
         return false;
     }
@@ -349,7 +544,7 @@ public abstract class TmfDataRequest extends TmfRequest implements ITmfDataReque
     @Override
     @SuppressWarnings("nls")
     public String toString() {
-        return "[TmfDataRequest(" + getRequestId() + "," + fEventTypeFilter.getEventType().getSimpleName() + "," + getStartIndex() + "," + getNbRequested()
+        return "[TmfDataRequest(" + fRequestId + "," + fDataType.getSimpleName() + "," + fIndex + "," + fNbRequested
                 + "," + getBlockSize() + ")]";
     }
 }
This page took 0.029848 seconds and 5 git commands to generate.