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: fbcc5fb9a0 [formerly 97b6a1a810 [formerly 7a7f86bfe6] [formerly fbcc5fb9a0 [formerly 7adb742310b662763315fc721d6d6f326b8ba160]]]
Former-commit-id: 97b6a1a810 [formerly 7a7f86bfe6]
Former-commit-id: 97b6a1a810
Former-commit-id: 2db9c6d959
This commit is contained in:
Roger Ferrel 2013-01-29 10:03:50 -06:00
parent f40885a2af
commit 658ac1f354
2 changed files with 233 additions and 61 deletions

View file

@ -23,8 +23,10 @@ package com.raytheon.viz.texteditor.dialogs;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.LinkedBlockingQueue;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
@ -97,8 +99,9 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* functionality. * functionality.
* 06/28/2010 3283 cjeanbap Implement window resize. * 06/28/2010 3283 cjeanbap Implement window resize.
* 25Sep2012 1196 lvenable Dialog refactor to prevent blocking. * 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. * off the UI thread.
* Changes to have multiple query jobs.
* </pre> * </pre>
* *
* @author lvenable * @author lvenable
@ -147,11 +150,6 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
*/ */
private long newestTime = -1L; 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 * custom mouse handling so we can do the required vertical bar
* non-scrolling. * non-scrolling.
@ -705,7 +703,6 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
// Keep this list the same size as disignatorList. // Keep this list the same size as disignatorList.
designatorTimeList.add(""); designatorTimeList.add("");
updateSelectionList(designatorTimeList); updateSelectionList(designatorTimeList);
dtlIndex = 0;
} }
/** /**
@ -723,6 +720,8 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
} }
designatorTimeList.setItem(0, value); designatorTimeList.setItem(0, value);
checkLoadBtn();
loadingTimes = false; loadingTimes = false;
if (!loadingProduct) { if (!loadingProduct) {
getShell().setCursor(null); 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 * Update the the chuck of times retrieved. The values should be inserted
* be inserted staring at dtlIndex+1. * starting at startIndex.
* *
* @param queryResponse * @param queryResponse
* @param startIndex
*/ */
private void updateAfterQuery(Message queryResponse) { private void updateAfterQuery(Message queryResponse, int startIndex) {
Property[] properties = queryResponse.getHeader().getProperties(); Property[] properties = queryResponse.getHeader().getProperties();
ArrayList<Long> times = new ArrayList<Long>(); ArrayList<Long> times = new ArrayList<Long>();
// We use this time to populate the "000" designator entry. // We use this time to populate the "000" designator entry.
if (properties != null) { if (properties != null) {
for (Property p : properties) { for (Property p : properties) {
@ -755,10 +755,9 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
String value = null; String value = null;
try { try {
int startIndex = dtlIndex; int index = startIndex;
int selectIndex = designatorList.getSelectionIndex(); int selectIndex = designatorList.getSelectionIndex();
for (Long time : times) { for (Long time : times) {
++dtlIndex;
if (time > 0) { if (time > 0) {
Calendar c = TimeTools.newCalendar(time); Calendar c = TimeTools.newCalendar(time);
value = String.format(TIME_FORMAT, c); value = String.format(TIME_FORMAT, c);
@ -767,11 +766,12 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
} else { } else {
value = DATA_NONE; value = DATA_NONE;
} }
designatorTimeList.setItem(dtlIndex, value); designatorTimeList.setItem(index, value);
++index;
} }
// Selected designator time updated check status of load buttons. // Selected designator time updated check status of load buttons.
if (selectIndex > startIndex && selectIndex <= dtlIndex) { if (selectIndex > startIndex && selectIndex <= index) {
checkLoadBtn(); checkLoadBtn();
} }
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
@ -1445,18 +1445,132 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
} }
/* /**
* Job to query for designator times. * Job to query for designator times.
*/ */
private class QueryRequests extends Job { 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<TimesRequest> timesRequestQueue = new LinkedBlockingQueue<AfosBrowserDlg.QueryRequests.TimesRequest>();
/**
* List of completed Times Requests that need to be processed to update
* the designator's hours.
*/
final LinkedBlockingQueue<TimesRequest> timesResultQueue = new LinkedBlockingQueue<AfosBrowserDlg.QueryRequests.TimesRequest>();
/**
* 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 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<QueryJob> queryJobList = Collections
.synchronizedList(new ArrayList<AfosBrowserDlg.QueryRequests.QueryJob>(
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; private boolean canceled = false;
/**
* The complete list of productIds to run in the request query.
*/
private java.util.List<String> productIds; private java.util.List<String> productIds;
/**
* Constructor.
*/
public QueryRequests() { public QueryRequests() {
super("QueryRequests"); super("QueryRequests");
setSystem(true); setSystem(true);
@ -1471,6 +1585,7 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
@Override @Override
protected IStatus run(IProgressMonitor monitor) { protected IStatus run(IProgressMonitor monitor) {
java.util.List<String> prodIds = null; java.util.List<String> prodIds = null;
TextDBQuery request = null;
synchronized (this) { synchronized (this) {
if (monitor.isCanceled()) { if (monitor.isCanceled()) {
@ -1478,6 +1593,8 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
} else { } else {
prodIds = productIds; prodIds = productIds;
productIds = null; productIds = null;
request = pendingRequest;
pendingRequest = null;
} }
} }
@ -1490,52 +1607,88 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
}); });
int cnt = 0; int cnt = 0;
int startIndex = 1;
// Queue up requests for getting Designator hours and start jobs
// to process them.
Iterator<String> iterator = prodIds.iterator(); Iterator<String> iterator = prodIds.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
String productId = iterator.next(); String productId = iterator.next();
if (canceled) { if (canceled) {
synchronized (this) { break;
canceled = false;
this.notify();
return Status.OK_STATUS;
}
} }
request.addProductId(productId); request.addProductId(productId);
++cnt; ++cnt;
if (cnt >= MAX_PRODUCTS_PER_QUERY || !iterator.hasNext()) { if (cnt >= MAX_PRODUCTS_PER_QUERY || !iterator.hasNext()) {
final Message queryResponse = request.executeQuery(); TimesRequest timesRequest = new TimesRequest(request,
if (!canceled) { startIndex);
VizApp.runAsync(new Runnable() { timesRequestQueue.add(timesRequest);
if (queryJobList.size() < MAX_QUERIES) {
@Override QueryJob queryJob = new QueryJob("");
public void run() { queryJobList.add(queryJob);
if (!canceled) { queryJob.schedule();
updateAfterQuery(queryResponse);
}
}
});
} }
request.clearProductIds(); request.clearProductIds();
startIndex += cnt;
cnt = 0; cnt = 0;
} }
} }
synchronized (this) { // Wait for all query jobs to finish and update results.
request = null; boolean finished = false;
while (!(finished || canceled)) {
if (!timesResultQueue.isEmpty()) {
final java.util.List<TimesRequest> resultList = new ArrayList<AfosBrowserDlg.QueryRequests.TimesRequest>();
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 @Override
public void run() { public void run() {
finishDesignatorTimeList(); 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; return Status.OK_STATUS;
} }
@ -1548,27 +1701,15 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
* @param productIds * @param productIds
* - List of products for the query. * - List of products for the query.
*/ */
public void addRequest(TextDBQuery request, public synchronized void addRequest(TextDBQuery request,
java.util.List<String> productIds) { java.util.List<String> productIds) {
synchronized (this) { if (getState() != Job.NONE) {
if (this.request != null) { cancel();
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();
} }
this.pendingRequest = request;
this.productIds = productIds;
schedule();
} }
/* /*
@ -1579,6 +1720,9 @@ public class AfosBrowserDlg extends CaveSWTDialog implements
@Override @Override
protected void canceling() { protected void canceling() {
canceled = true; canceled = true;
for (QueryJob query : queryJobList) {
query.canceled = true;
}
} }
} }
} }

View file

@ -39,7 +39,7 @@ import com.raytheon.uf.common.message.Property;
* Nov 3, 2008 jkorman Initial creation * Nov 3, 2008 jkorman Initial creation
* 28May2010 cjeanbap Added operational functionality. * 28May2010 cjeanbap Added operational functionality.
* 02Aug2010 2187 cjeanbap Update variable/method signature to be consistent. * 02Aug2010 2187 cjeanbap Update variable/method signature to be consistent.
* 22Jan2013 1496 rferrel Added method clearProductIds * 29Jan2013 1496 rferrel Added methods clearProductIds and clone.
* *
* </pre> * </pre>
* *
@ -91,6 +91,34 @@ public class TextDBQuery {
queryTransport = transport; 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<String>(productIds);
}
return tdq;
}
/** /**
* @return the queryViewName * @return the queryViewName
*/ */