Issue #1596 Do not reschedule bandwidth allocations when a subscription is removed

Change-Id: I4016034e6bdc5e8acf4936a0f786906611e7ad41

Former-commit-id: 4be6c12ac6 [formerly 714ea1c8d8] [formerly 4be6c12ac6 [formerly 714ea1c8d8] [formerly 6e2f69939f [formerly 5f87319abc3712667abc6b454f49882b0f3fb45f]]]
Former-commit-id: 6e2f69939f
Former-commit-id: d0ecd69456 [formerly 1ef440f8ee]
Former-commit-id: f14bedec28
This commit is contained in:
Dustin Johnson 2013-02-14 11:55:40 -06:00
parent 9213ea18f2
commit 12d4b055f6
5 changed files with 179 additions and 72 deletions

View file

@ -30,13 +30,12 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.uf.viz.datadelivery.actions.BandwidthScheduleGraphAction;
/**
*
* This is a utility class used to get data for the bandwidth graph it extends
* the Thread class so you can retrieve data on a separate thread to keep the UI
* thread from being blocked.
* This is a utility class used to get data for the bandwidth graph it
* implements {@link Runnable} so you can retrieve data on a separate thread to
* keep the UI thread from being blocked.
*
* <pre>
*
@ -45,19 +44,20 @@ import com.raytheon.uf.viz.datadelivery.actions.BandwidthScheduleGraphAction;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 12, 2012 1269 lvenable Initial creation
* Feb 14, 2013 1596 djohnson Remove sysouts, correct statusHandler class, handle null response.
*
* </pre>
*
* @author lvenable
* @version 1.0
*/
public class GraphDataUtil extends Thread {
public class GraphDataUtil implements Runnable {
/** UFStatus handler */
private final IUFStatusHandler statusHandler = UFStatus
.getHandler(BandwidthScheduleGraphAction.class);
.getHandler(GraphDataUtil.class);
/** Graph data request object */
private GraphDataRequest request;
private final GraphDataRequest request = new GraphDataRequest();
/** Graph data response object */
private GraphDataResponse response;
@ -79,7 +79,6 @@ public class GraphDataUtil extends Thread {
* thread.
*/
public GraphDataUtil(IDataUpdated dataUpdatedCB) {
request = new GraphDataRequest();
this.dataUpdatedCB = dataUpdatedCB;
}
@ -99,7 +98,10 @@ public class GraphDataUtil extends Thread {
*/
public void retrieveData() {
response = sendRequest(request);
graphData = response.getGraphData();
if (response != null) {
graphData = response.getGraphData();
}
}
/**
@ -155,14 +157,13 @@ public class GraphDataUtil extends Thread {
/**
* Thread run method to retrieve the graph data.
*/
@Override
public void run() {
System.out.println("Thread - retrieving data...");
retrieveData();
if (dataUpdatedCB != null) {
dataUpdatedCB.dataUpdated();
}
System.out.println("Thread - DONE retrieving data...");
}
}

View file

@ -21,8 +21,6 @@ import java.util.regex.Pattern;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
@ -101,6 +99,7 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.util.BandwidthUtil;
* Jan 30, 2013 1501 djohnson Fix broken calculations for determining required latency.
* Feb 05, 2013 1580 mpduff EventBus refactor.
* Feb 14, 2013 1595 djohnson Check with BandwidthUtil whether or not to reschedule subscriptions on update.
* Feb 14, 2013 1596 djohnson Do not reschedule allocations when a subscription is removed.
* </pre>
*
* @author dhladky
@ -560,7 +559,7 @@ abstract class BandwidthManager extends
List<BandwidthSubscription> l = bandwidthDao
.getBandwidthSubscriptionByRegistryId(event.getId());
if (!l.isEmpty()) {
remove(l, true);
remove(l);
}
}
}
@ -736,7 +735,7 @@ abstract class BandwidthManager extends
// See if the subscription was inactivated or unscheduled..
// Need to remove BandwidthReservations for this
// subscription.
return remove(bandwidthSubscriptions, true);
return remove(bandwidthSubscriptions);
} else {
// Compare the 'updated' Subscription with the stored
@ -761,8 +760,7 @@ abstract class BandwidthManager extends
// OK, have to remove the old Subscriptions and add the new
// ones..
List<BandwidthAllocation> unscheduled = remove(
bandwidthSubscriptions, false);
List<BandwidthAllocation> unscheduled = remove(bandwidthSubscriptions);
// No need to check anything else since all the
// BandwidthSubscription's have been replaced.
unscheduled.addAll(schedule(subscription));
@ -794,10 +792,10 @@ abstract class BandwidthManager extends
newCycles.removeAll(commonCycles);
// Remove the old cycles, add the new ones...
if (oldCycles.size() > 0) {
if (!oldCycles.isEmpty()) {
// Create a List of SubscriptionDaos that need to be
// removed..
List<BandwidthSubscription> remove = new ArrayList<BandwidthSubscription>();
List<BandwidthSubscription> bandwidthSubscriptionToRemove = new ArrayList<BandwidthSubscription>();
BandwidthSubscription bandwidthSubscription = null;
Iterator<BandwidthSubscription> itr = bandwidthSubscriptions
.iterator();
@ -805,11 +803,11 @@ abstract class BandwidthManager extends
bandwidthSubscription = itr.next();
if (oldCycles.contains(bandwidthSubscription
.getCycle())) {
remove.add(bandwidthSubscription);
bandwidthSubscriptionToRemove.add(bandwidthSubscription);
itr.remove();
}
}
unscheduled.addAll(remove(remove, true));
unscheduled.addAll(remove(bandwidthSubscriptionToRemove));
}
if (newCycles.size() > 0) {
@ -846,63 +844,15 @@ abstract class BandwidthManager extends
*
* @param bandwidthSubscriptions
* The subscriptionDao's to remove.
* @param reschedule
* @return
*/
private List<BandwidthAllocation> remove(
List<BandwidthSubscription> bandwidthSubscriptions,
boolean reschedule) {
List<BandwidthSubscription> bandwidthSubscriptions) {
List<BandwidthAllocation> unscheduled = new ArrayList<BandwidthAllocation>();
// If we need to reschedule other bandwidth reservations when we
// remove the provided BandwidthSubscription's then we have to retrieve
// all the SubscriptionRetrieval records that are scheduled for
// the same base time.
if (reschedule) {
// First create a map of base times to subscriptions
Multimap<Calendar, BandwidthSubscription> map = ArrayListMultimap
.create();
for (BandwidthSubscription bandwidthSubscription : bandwidthSubscriptions) {
Calendar time = bandwidthSubscription.getBaseReferenceTime();
map.put(time, bandwidthSubscription);
}
// Now process each time group by dataset..
for (Calendar baseTime : map.keySet()) {
// For each date, get a unique set of provider & dataset name
Set<String> providerDataSet = new HashSet<String>();
for (BandwidthSubscription bandwidthSubscription : map
.get(baseTime)) {
String key = bandwidthSubscription.getProvider() + "::"
+ bandwidthSubscription.getDataSetName();
providerDataSet.add(key);
bandwidthDaoUtil.remove(bandwidthSubscription);
}
// Query for and reschedule any SubscriptionRetrieval
// Objects associated with the Queried BandwidthSubscription's
for (String providerDataSetName : providerDataSet) {
String[] key = providerDataSetName.split("::");
String provider = key[0];
String dataSetName = key[1];
List<BandwidthSubscription> m = bandwidthDao
.getBandwidthSubscriptions(provider, dataSetName,
baseTime);
unscheduled.addAll(aggregate(m));
}
}
} else {
for (BandwidthSubscription bandwidthSubscription : bandwidthSubscriptions) {
bandwidthDaoUtil.remove(bandwidthSubscription);
}
for (BandwidthSubscription bandwidthSubscription : bandwidthSubscriptions) {
bandwidthDaoUtil.remove(bandwidthSubscription);
}
return unscheduled;

View file

@ -32,6 +32,7 @@ import com.raytheon.uf.edex.datadelivery.retrieval.RetrievalManagerNotifyEvent;
* change the event listener type.
* Oct 26, 2012 1286 djohnson Return list of unscheduled allocations.
* Feb 05, 2013 1580 mpduff EventBus refactor.
* Feb 14, 2013 1596 djohnson Warn log when unable to find a SubscriptionRetrieval.
*
* </pre>
*
@ -136,6 +137,12 @@ public class RetrievalManager {
SubscriptionRetrieval subscriptionRetrieval = bandwidthDao
.getSubscriptionRetrieval(eventId);
if (subscriptionRetrieval == null) {
statusHandler.warn("Unable to find SubscriptionRetrieval by id ["
+ eventId + "]");
return;
}
// Update the SubscriptionRetrieval in the database since the Retrievals
// were completed outside the Bandwidth subsystem.
subscriptionRetrieval.setStatus(RetrievalStatus.FULFILLED);

View file

@ -21,6 +21,7 @@ package com.raytheon.uf.edex.datadelivery.bandwidth;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
@ -98,6 +99,7 @@ import com.raytheon.uf.edex.datadelivery.retrieval.RetrievalManagerNotifyEvent;
* Jan 28, 2013 1530 djohnson Test that all allocations are unscheduled for subscription that doesn't fully schedule.
* Jan 30, 2013 1501 djohnson Fix broken calculations for determining required latency.
* Feb 14, 2013 1595 djohnson Fix expired subscription updates that weren't scheduling retrievals.
* Feb 14, 2013 1596 djohnson Add test duplicating errors deleting multiple subscriptions for the same provider/dataset.
*
* </pre>
*
@ -776,6 +778,85 @@ public class BandwidthManagerIntTest extends AbstractBandwidthManagerIntTest {
subscriptionDaosAfterDelete.size());
}
/**
* Test case derived from Redmine #1596: There were 5 or 6 subscriptions
* that were deleted simultaneously. All subscriptions were removed from the
* Subscription Manager dialog...however, 2 subscriptions remained
* 'scheduled' or listed on the Bandwidth Utilization graph. After selecting
* the deleted subscription in the Bandwidth Utilization graph, the view
* selected subscriptions option was selected. No subscriptions were
* displayed, as expected...even though the subscription was listed in the
* Bandwidth Utilization graph.
*/
@Test
public void testDeletedSubscriptionsToSameProviderDataSetHaveSubscriptionDaosDeletedFromDatabase()
throws Exception {
final int numberOfSubscriptionsWithSameProviderDataSet = 4;
final Subscription templateSubscription = createSubscriptionThatFillsUpABucket();
final Network route = templateSubscription.getRoute();
templateSubscription.setDataSetSize(templateSubscription
.getDataSetSize()
/ numberOfSubscriptionsWithSameProviderDataSet);
templateSubscription.getTime().setCycleTimes(Arrays.asList(0, 12));
int lastKnownNumberOfBandwidthAllocations = 0;
final Subscription[] subscriptions = new Subscription[numberOfSubscriptionsWithSameProviderDataSet];
for (int i = 0; i < numberOfSubscriptionsWithSameProviderDataSet; i++) {
final Subscription currentSubscription = new Subscription(
templateSubscription, "ILookLikeTheOtherGuys-" + i);
subscriptions[i] = currentSubscription;
bandwidthManager.schedule(currentSubscription);
// Make sure some data is scheduled for retrieval
final int currentNumberOfBandwidthAllocations = bandwidthDao
.getBandwidthAllocations(route).size();
assertThat(currentNumberOfBandwidthAllocations,
is(greaterThan(lastKnownNumberOfBandwidthAllocations)));
// Update last known number of bandwidth allocations, so we can
// continue verifying more is scheduled
lastKnownNumberOfBandwidthAllocations = currentNumberOfBandwidthAllocations;
}
// Schedule two subscription deletions to occur at the same time
final CountDownLatch waitForAllThreadsToStartLatch = new CountDownLatch(
numberOfSubscriptionsWithSameProviderDataSet);
final CountDownLatch deletesFinishedLatch = new CountDownLatch(
numberOfSubscriptionsWithSameProviderDataSet);
for (int i = 0; i < numberOfSubscriptionsWithSameProviderDataSet; i++) {
final int iteration = i;
final Thread deleteSubscriptionThread = new Thread() {
@Override
public void run() {
waitForAllThreadsToStartLatch.countDown();
try {
sendDeletedSubscriptionEvent(subscriptions[iteration]);
} finally {
deletesFinishedLatch.countDown();
}
}
};
// Delete the subscription! Each thread will wait to perform the
// deletion until all threads are started.
deleteSubscriptionThread.start();
}
// Wait for the deletion threads to finish
deletesFinishedLatch.await();
// Better not be any bandwidth subscriptions left, or bandwidth
// allocations
assertThat(bandwidthDao.getBandwidthSubscriptions(), is(empty()));
assertThat(bandwidthDao.getBandwidthAllocations(route), is(empty()));
}
/**
* Subscriptions that are deleted should have all of their bandwidth
* allocations removed deleted.

View file

@ -0,0 +1,68 @@
/**
* 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.uf.edex.datadelivery.bandwidth.retrieval;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Test;
import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDao;
import com.raytheon.uf.edex.datadelivery.retrieval.RetrievalManagerNotifyEvent;
/**
* Test {@link RetrievalManager}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 14, 2013 1543 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class RetrievalManagerTest {
private static final long EVENT_ID = 1L;
private final IBandwidthDao dao = mock(IBandwidthDao.class);
private final RetrievalManagerNotifyEvent event = new RetrievalManagerNotifyEvent();
{
event.setId(Long.valueOf(EVENT_ID).toString());
}
@Test
public void noSubscriptionRetrievalByEventIdDoesNotThrowException() {
when(dao.getSubscriptionRetrieval(EVENT_ID)).thenReturn(null);
RetrievalManager retrievalManager = new RetrievalManager(dao,
new Object());
retrievalManager.retrievalCompleted(event);
}
}