From e00f394424bcc8671223d1af4eaa1e3d613e6f63 Mon Sep 17 00:00:00 2001 From: Ben Steffensmeier Date: Wed, 29 Oct 2014 14:22:13 -0500 Subject: [PATCH] Omaha #3668 Give grid a custom job pool. Former-commit-id: b41b28ed5777b0c7f337c79c4986f86e4722838d [formerly 14e82b9f400b47b4f446bf1c5c5e729cf442b153] Former-commit-id: 596578281ab3e9aada193d184dc60b82dc189c58 --- .../rsc/general/GridDataRequestJobPool.java | 128 ++++++++++++++++++ .../rsc/general/GridDataRequestRunner.java | 85 +++++------- 2 files changed, 165 insertions(+), 48 deletions(-) create mode 100644 cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/GridDataRequestJobPool.java diff --git a/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/GridDataRequestJobPool.java b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/GridDataRequestJobPool.java new file mode 100644 index 0000000000..961d1a30d2 --- /dev/null +++ b/cave/com.raytheon.viz.grid/src/com/raytheon/viz/grid/rsc/general/GridDataRequestJobPool.java @@ -0,0 +1,128 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.viz.grid.rsc.general; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +/** + * A pool of {@link Job} that executes {@link GridDataRequestRunner}s with a + * scheduling pattern that is ideal for smooth user interaction. This object + * expects {@link #schedule(GridDataRequestRunner)} to be called each time data + * is needed that is not yet available(primarily when the frame is displayed). + * Calling {@link #schedule(GridDataRequestRunner)} causes the runner to be + * bumped to the front of the queue so that data will be ready as soon as + * possible. This causes runners that are not being displayed to frequently get + * bumped to the back of the queue, which is desired since the user does not + * need that data yet. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date          Ticket#  Engineer    Description
+ * ------------- -------- ----------- --------------------------
+ * Oct 29, 2014  3668     bsteffen    Initial creation
+ * 
+ * 
+ * + * @author bsteffen + * @version 1.0 + */ +public class GridDataRequestJobPool { + + private static final int POOL_SIZE = Integer.getInteger( + "grid.request.pool.size", 10); + + private static final GridDataRequestJobPool instance = new GridDataRequestJobPool(); + + public static void schedule(GridDataRequestRunner runner) { + instance.scheduleRunner(runner); + } + + protected LinkedBlockingQueue jobQueue = new LinkedBlockingQueue(); + + protected List runners = new LinkedList<>(); + + private GridDataRequestJobPool(){ + for (int i = 0; i * @@ -47,21 +46,15 @@ import com.raytheon.uf.viz.core.jobs.JobPool; * Jun 24, 2013 2140 randerso Moved safe name code into AbstractVizResource * Oct 07, 2014 3668 bclement uses executor instead of eclipse job * renamed to GridDataRequestRunner - * Oct 23, 2014 3668 bsteffen replace executor with job pool so user - * sees progress. + * Oct 29, 2014 3668 bsteffen replace executor with custom job pool. * * * * @author bsteffen * @version 1.0 + * @see GridDataRequestJobPool */ -class GridDataRequestRunner implements Runnable { - - private static final int POOL_SIZE = Integer.getInteger( - "grid.request.pool.size", 10); - - private static final JobPool jobPool = new JobPool("Requesting Grid Data", - POOL_SIZE); +class GridDataRequestRunner { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(GridDataRequestRunner.class); @@ -80,6 +73,8 @@ class GridDataRequestRunner implements Runnable { // been notified.) public boolean exceptionHandled = false; + public boolean isRunning = false; + public GridDataRequest(DataTime time, List pdos) { this.time = time; if (pdos == null) { @@ -91,21 +86,12 @@ class GridDataRequestRunner implements Runnable { } public boolean shouldRequest() { - return (gridData == null) && (exception == null); + return (gridData == null) && (exception == null) + && (isRunning == false); } } - /** - * This class is not designed to handle multiple requests concurrently. To - * ensure this doesn't happen we track when it is scheduled and do not - * schedule again. It would have been simpler to synchronize the run method - * but that ties up threads from the pool that other resources should use. - * So we don't leave dangling requests this should only be modified while - * synchronized on requests. - */ - private volatile boolean scheduled = false; - private AbstractGridResource resource; private List requests = new ArrayList(); @@ -114,42 +100,49 @@ class GridDataRequestRunner implements Runnable { this.resource = resource; } - @Override - public void run() { - for (GridDataRequest request = getNext(); request != null; request = getNext()) { - try { - request.gridData = resource.getData(request.time, request.pdos); - if (request.gridData == null) { - /* - * need to remove unfulfillable requests to avoid infinite - * loop. - */ - synchronized (requests) { - requests.remove(request); - } - } else { - resource.issueRefresh(); + /** + * Attempt to process a request if there are any that need to be processed + * + * @return true if a request was processed or false if no requests need to + * be processed. + */ + public boolean processOneRequest() { + GridDataRequest request = getNext(); + if (request == null) { + return false; + } + try { + request.gridData = resource.getData(request.time, request.pdos); + if (request.gridData == null) { + /* need to remove unfulfillable requests to avoid infinite loop. */ + synchronized (requests) { + requests.remove(request); } - } catch (VizException e) { - request.exception = e; + } else { resource.issueRefresh(); } + } catch (VizException e) { + request.exception = e; + resource.issueRefresh(); + } finally { + request.isRunning = false; } + return true; } /** - * Get the next request that should be sent + * Get the next request that should be processed * - * @return null if no request should be sent + * @return null if no request should be processed */ protected GridDataRequest getNext() { synchronized (requests) { for (GridDataRequest request : requests) { if (request.shouldRequest()) { + request.isRunning = true; return request; } } - scheduled = false; } return null; } @@ -181,9 +174,8 @@ class GridDataRequestRunner implements Runnable { if ((request.exception != null) && !request.exceptionHandled) { handleExceptions(); } - if (!scheduled && request.shouldRequest()) { - scheduled = true; - jobPool.schedule(this); + if (request.shouldRequest()) { + GridDataRequestJobPool.schedule(this); } } return null; @@ -268,9 +260,6 @@ class GridDataRequestRunner implements Runnable { public void stopAndClear() { synchronized (requests) { requests.clear(); - if (jobPool.cancel(this)) { - scheduled = false; - } } }