From 658ac1f354bc3620b2635ae2993e7d2367311590 Mon Sep 17 00:00:00 2001 From: Roger Ferrel Date: Tue, 29 Jan 2013 10:03:50 -0600 Subject: [PATCH] Issue #1496 Changes to allow multiple query jobs. (Reduced long queries from 30 to 5 seconds.) Changes to use fewer synchronized blocks. Change-Id: I854a5ff9d34be63e46d26f3d78953bc3b8cc796a Former-commit-id: fbcc5fb9a0b3d5ca2291027369f5aa67221fdf1c [formerly 97b6a1a8106d07905ec6b51a46cbc67e64d0b85d [formerly 7a7f86bfe62b10a5a92696b8f62c46e623223996] [formerly fbcc5fb9a0b3d5ca2291027369f5aa67221fdf1c [formerly 7adb742310b662763315fc721d6d6f326b8ba160]]] Former-commit-id: 97b6a1a8106d07905ec6b51a46cbc67e64d0b85d [formerly 7a7f86bfe62b10a5a92696b8f62c46e623223996] Former-commit-id: 97b6a1a8106d07905ec6b51a46cbc67e64d0b85d Former-commit-id: 2db9c6d95949bb8043b6ff42916bce6d927f53a1 --- .../texteditor/dialogs/AfosBrowserDlg.java | 264 ++++++++++++++---- .../edex/services/textdbsrv/TextDBQuery.java | 30 +- 2 files changed, 233 insertions(+), 61 deletions(-) diff --git a/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/AfosBrowserDlg.java b/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/AfosBrowserDlg.java index eb6f7ea3c0..0a0c1f2511 100644 --- a/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/AfosBrowserDlg.java +++ b/cave/com.raytheon.viz.texteditor/src/com/raytheon/viz/texteditor/dialogs/AfosBrowserDlg.java @@ -23,8 +23,10 @@ package com.raytheon.viz.texteditor.dialogs; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.Iterator; import java.util.SortedSet; +import java.util.concurrent.LinkedBlockingQueue; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -97,8 +99,9 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog; * functionality. * 06/28/2010 3283 cjeanbap Implement window resize. * 25Sep2012 1196 lvenable Dialog refactor to prevent blocking. - * 22Jan2013 1496 rferrel Changes to designator hours query + * 29Jan2013 1496 rferrel Changes to designator hours query * off the UI thread. + * Changes to have multiple query jobs. * * * @author lvenable @@ -147,11 +150,6 @@ public class AfosBrowserDlg extends CaveSWTDialog implements */ private long newestTime = -1L; - /** - * Index of designator who time is being updated. - */ - private int dtlIndex; - /** * custom mouse handling so we can do the required vertical bar * non-scrolling. @@ -705,7 +703,6 @@ public class AfosBrowserDlg extends CaveSWTDialog implements // Keep this list the same size as disignatorList. designatorTimeList.add(""); updateSelectionList(designatorTimeList); - dtlIndex = 0; } /** @@ -723,6 +720,8 @@ public class AfosBrowserDlg extends CaveSWTDialog implements } designatorTimeList.setItem(0, value); + checkLoadBtn(); + loadingTimes = false; if (!loadingProduct) { getShell().setCursor(null); @@ -730,16 +729,17 @@ public class AfosBrowserDlg extends CaveSWTDialog implements } /** - * Update the the next chuck of times retrieved. Assume these values should - * be inserted staring at dtlIndex+1. + * Update the the chuck of times retrieved. The values should be inserted + * starting at startIndex. * * @param queryResponse + * @param startIndex */ - private void updateAfterQuery(Message queryResponse) { + private void updateAfterQuery(Message queryResponse, int startIndex) { Property[] properties = queryResponse.getHeader().getProperties(); - ArrayList times = new ArrayList(); + // We use this time to populate the "000" designator entry. if (properties != null) { for (Property p : properties) { @@ -755,10 +755,9 @@ public class AfosBrowserDlg extends CaveSWTDialog implements String value = null; try { - int startIndex = dtlIndex; + int index = startIndex; int selectIndex = designatorList.getSelectionIndex(); for (Long time : times) { - ++dtlIndex; if (time > 0) { Calendar c = TimeTools.newCalendar(time); value = String.format(TIME_FORMAT, c); @@ -767,11 +766,12 @@ public class AfosBrowserDlg extends CaveSWTDialog implements } else { value = DATA_NONE; } - designatorTimeList.setItem(dtlIndex, value); + designatorTimeList.setItem(index, value); + ++index; } // Selected designator time updated check status of load buttons. - if (selectIndex > startIndex && selectIndex <= dtlIndex) { + if (selectIndex > startIndex && selectIndex <= index) { checkLoadBtn(); } } catch (IllegalArgumentException ex) { @@ -1445,18 +1445,132 @@ public class AfosBrowserDlg extends CaveSWTDialog implements } - /* + /** * Job to query for designator times. */ private class QueryRequests extends Job { + /* + * This contains the query command for getting a some of the Designator + * times for the query and where in the designator time list the times + * belong. + */ + private class TimesRequest { + /** + * Clone copy of the query passed to the constructor. + */ + protected TextDBQuery query; + + /** + * The index in the Designator Time list where to start placing the + * results. + */ + protected int startIndex; + + /** + * Query results. + */ + protected Message queryResults; + + public TimesRequest(TextDBQuery query, int startIndex) { + this.query = query.clone(); + this.startIndex = startIndex; + } + } + + /** + * List of pending Times Requests needed to populate the designator + * times. + */ + final LinkedBlockingQueue timesRequestQueue = new LinkedBlockingQueue(); + + /** + * List of completed Times Requests that need to be processed to update + * the designator's hours. + */ + final LinkedBlockingQueue timesResultQueue = new LinkedBlockingQueue(); + + /** + * A job for taking a pending TimesRequest, perform the query and then + * place it on the result list. + */ + private class QueryJob extends Job { + /** + * Flag to indicate active request has been canceled. + */ + private boolean canceled = false; + + /** + * Constructor. + * + * @param name + */ + public QueryJob(String name) { + super("QueryJob"); + setSystem(true); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime + * .IProgressMonitor) + */ + @Override + protected IStatus run(IProgressMonitor monitor) { + while (true) { + TimesRequest timesRequest = timesRequestQueue.poll(); + if (timesRequest == null || canceled) { + queryJobList.remove(this); + return Status.OK_STATUS; + } + timesRequest.queryResults = timesRequest.query + .executeQuery(); + timesRequest.query = null; + + if (!canceled) { + timesResultQueue.add(timesRequest); + } + } + } + } + + /** + * Maximum number of product ids to place in a Times Request. + */ private final int MAX_PRODUCTS_PER_QUERY = 25; - private TextDBQuery request = null; + /** + * Maximum number of jobs to service the Times Request. + */ + private final int MAX_QUERIES = 5; + /** + * Active Query Jobs. The list must be synchronized since it is modified + * in multiple threads outside of any synchronized block. + */ + private final java.util.List queryJobList = Collections + .synchronizedList(new ArrayList( + MAX_QUERIES)); + + /** + * The pending request for getting designator hours. + */ + private TextDBQuery pendingRequest = null; + + /** + * Flag to indicate the current request is canceled. + */ private boolean canceled = false; + /** + * The complete list of productIds to run in the request query. + */ private java.util.List productIds; + /** + * Constructor. + */ public QueryRequests() { super("QueryRequests"); setSystem(true); @@ -1471,6 +1585,7 @@ public class AfosBrowserDlg extends CaveSWTDialog implements @Override protected IStatus run(IProgressMonitor monitor) { java.util.List prodIds = null; + TextDBQuery request = null; synchronized (this) { if (monitor.isCanceled()) { @@ -1478,6 +1593,8 @@ public class AfosBrowserDlg extends CaveSWTDialog implements } else { prodIds = productIds; productIds = null; + request = pendingRequest; + pendingRequest = null; } } @@ -1490,52 +1607,88 @@ public class AfosBrowserDlg extends CaveSWTDialog implements }); int cnt = 0; + int startIndex = 1; + // Queue up requests for getting Designator hours and start jobs + // to process them. Iterator iterator = prodIds.iterator(); while (iterator.hasNext()) { String productId = iterator.next(); if (canceled) { - synchronized (this) { - canceled = false; - this.notify(); - return Status.OK_STATUS; - } + break; } request.addProductId(productId); ++cnt; if (cnt >= MAX_PRODUCTS_PER_QUERY || !iterator.hasNext()) { - final Message queryResponse = request.executeQuery(); - if (!canceled) { - VizApp.runAsync(new Runnable() { - - @Override - public void run() { - if (!canceled) { - updateAfterQuery(queryResponse); - } - } - }); + TimesRequest timesRequest = new TimesRequest(request, + startIndex); + timesRequestQueue.add(timesRequest); + if (queryJobList.size() < MAX_QUERIES) { + QueryJob queryJob = new QueryJob(""); + queryJobList.add(queryJob); + queryJob.schedule(); } request.clearProductIds(); + startIndex += cnt; cnt = 0; } } - synchronized (this) { - request = null; + // Wait for all query jobs to finish and update results. + boolean finished = false; + while (!(finished || canceled)) { + if (!timesResultQueue.isEmpty()) { + final java.util.List resultList = new ArrayList(); + timesResultQueue.drainTo(resultList); + + VizApp.runAsync(new Runnable() { + + @Override + public void run() { + for (TimesRequest result : resultList) { + if (canceled) { + break; + } + updateAfterQuery(result.queryResults, + result.startIndex); + } + } + }); + } + + if (queryJobList.size() > 0) { + synchronized (this) { + try { + wait(200L); + } catch (InterruptedException e) { + statusHandler.handle(Priority.PROBLEM, + e.getLocalizedMessage(), e); + } + } + } else { + finished = timesResultQueue.isEmpty(); + } } - VizApp.runAsync(new Runnable() { + if (!canceled) { + VizApp.runAsync(new Runnable() { - @Override - public void run() { - finishDesignatorTimeList(); - } - }); + @Override + public void run() { + finishDesignatorTimeList(); + } + }); + } + // Make sure everything is in proper state for the next time job is + // schedule. + timesRequestQueue.clear(); + timesResultQueue.clear(); + queryJobList.clear(); + canceled = false; return Status.OK_STATUS; } @@ -1548,27 +1701,15 @@ public class AfosBrowserDlg extends CaveSWTDialog implements * @param productIds * - List of products for the query. */ - public void addRequest(TextDBQuery request, + public synchronized void addRequest(TextDBQuery request, java.util.List productIds) { - synchronized (this) { - if (this.request != null) { - if (getState() != Job.NONE) { - cancel(); - while (request != null && getState() != Job.NONE) { - try { - wait(100L); - } catch (InterruptedException e) { - AfosBrowserDlg.statusHandler.handle( - Priority.PROBLEM, - e.getLocalizedMessage(), e); - } - } - } - } - this.request = request; - this.productIds = productIds; - schedule(); + if (getState() != Job.NONE) { + cancel(); } + + this.pendingRequest = request; + this.productIds = productIds; + schedule(); } /* @@ -1579,6 +1720,9 @@ public class AfosBrowserDlg extends CaveSWTDialog implements @Override protected void canceling() { canceled = true; + for (QueryJob query : queryJobList) { + query.canceled = true; + } } } } \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.textdbsrv/src/com/raytheon/uf/edex/services/textdbsrv/TextDBQuery.java b/edexOsgi/com.raytheon.uf.edex.textdbsrv/src/com/raytheon/uf/edex/services/textdbsrv/TextDBQuery.java index 2c820c77d0..a1bdfe48f8 100644 --- a/edexOsgi/com.raytheon.uf.edex.textdbsrv/src/com/raytheon/uf/edex/services/textdbsrv/TextDBQuery.java +++ b/edexOsgi/com.raytheon.uf.edex.textdbsrv/src/com/raytheon/uf/edex/services/textdbsrv/TextDBQuery.java @@ -39,7 +39,7 @@ import com.raytheon.uf.common.message.Property; * Nov 3, 2008 jkorman Initial creation * 28May2010 cjeanbap Added operational functionality. * 02Aug2010 2187 cjeanbap Update variable/method signature to be consistent. - * 22Jan2013 1496 rferrel Added method clearProductIds + * 29Jan2013 1496 rferrel Added methods clearProductIds and clone. * * * @@ -91,6 +91,34 @@ public class TextDBQuery { queryTransport = transport; } + /* + * (non-Javadoc) + * + * @see java.lang.Object#clone() + */ + public TextDBQuery clone() { + TextDBQuery tdq = new TextDBQuery(queryTransport); + tdq.queryViewName = this.queryViewName; + tdq.queryOpName = this.queryOpName; + tdq.querySubObName = this.querySubObName; + tdq.queryTimeFormatName = this.queryTimeFormatName; + tdq.queryTimeFormat = this.queryTimeFormat; + tdq.queryAfosCmd = this.queryAfosCmd; + tdq.queryWmoId = this.queryWmoId; + tdq.querySite = this.querySite; + tdq.queryHour = this.queryHour; + tdq.queryHdrTime = this.queryHdrTime; + tdq.queryBBB = this.queryBBB; + tdq.queryNnnXxx = this.queryNnnXxx; + tdq.queryFullDataRead = this.queryFullDataRead; + tdq.queryOperationalMode = this.queryOperationalMode; + tdq.queryProduct = this.queryProduct; + if (productIds != null) { + tdq.productIds = new ArrayList(productIds); + } + return tdq; + } + /** * @return the queryViewName */