com.bigdata.service.AbstractServiceLoadHelperWithScores Maven / Gradle / Ivy
/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Dec 10, 2008
*/
package com.bigdata.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
import org.apache.log4j.Logger;
/**
* The default implementation used when scores are available.
*
* @author Bryan Thompson
* @version $Id$
*/
abstract public class AbstractServiceLoadHelperWithScores extends
AbstractServiceLoadHelper {
protected static final Logger log = Logger
.getLogger(AbstractServiceLoadHelperWithScores.class);
protected static final boolean INFO = log.isInfoEnabled();
// protected static final boolean DEBUG = log.isDebugEnabled();
final protected UUID knownGood;
final protected ServiceScore[] scores;
/**
* @param joinTimeout
* The maximum time in milliseconds
* @param knownGood
* A service that is known to be active and NOT excluded from the
* request to be posed.
* @param scores
* Scores for the services in ascending order (least utilized to
* most utilized).
*/
protected AbstractServiceLoadHelperWithScores(final long joinTimeout,
final UUID knownGood, final ServiceScore[] scores) {
super(joinTimeout);
if (knownGood == null)
throw new IllegalArgumentException();
if (scores == null)
throw new IllegalArgumentException();
if (scores.length == 0)
throw new IllegalArgumentException();
this.knownGood = knownGood;
this.scores = scores;
}
/**
* Handles the case when we have per-service scores.
*
* Note: Pre-condition: the service scores must exist and there must be at
* least one active service with a score that is not excluded (the
* {@link #knownGood} service).
*
* @param minCount
* @param maxCount
* @param exclude
* @return
*
* @throws TimeoutException
* @throws InterruptedException
*/
public UUID[] getUnderUtilizedDataServices(final int minCount,
final int maxCount, final UUID exclude) throws TimeoutException,
InterruptedException {
if (exclude != null && knownGood.equals(exclude)) {
throw new IllegalArgumentException();
}
/*
* Decide on the set of active services that we consider to be
* under-utilized based on their scores. When maxCount is non-zero, this
* set will be no larger than maxCount. When maxCount is zero the set
* will contain all services that satisify the "under-utilized"
* criteria.
*/
final List underUtilized = new ArrayList(Math.max(
scores.length, Math.max(minCount, maxCount)));
int nok = 0;
for (int i = 0; i < scores.length; i++) {
final ServiceScore score = scores[i];
// excluded?
if (score.serviceUUID.equals(exclude))
continue;
// not active?
if (!isActiveDataService(score.serviceUUID))
continue;
if (isUnderUtilizedDataService(score, scores)) {
underUtilized.add(score.serviceUUID);
nok++;
}
if (maxCount > 0 && nok >= maxCount) {
if (INFO)
log.info("Satisifed maxCount=" + maxCount);
break;
}
if (minCount > 0 && maxCount == 0 && nok >= minCount) {
if (INFO)
log.info("Satisifed minCount=" + minCount);
break;
}
}
if (INFO)
log.info("Found " + underUtilized.size()
+ " under-utilized and non-excluded services");
if (minCount > 0 && underUtilized.isEmpty()) {
/*
* Since we did not find anything we default to the one service that
* provided as our fallback. This service might not be
* under-utilized and it might no longer be active, but it is the
* service that we are going to return.
*/
assert knownGood != null;
log.warn("Will report fallback service: " + knownGood);
underUtilized.add(knownGood);
}
/*
* Populate the return array, choosing at least minCount services and
* repeating services if necessary.
*
* Note: We return at least minCount UUIDs, even if we have to return
* the same UUID in each slot.
*/
final UUID[] uuids = new UUID[Math.max(minCount, nok)];
int n = 0, i = 0;
while (n < uuids.length) {
final UUID tmp = underUtilized.get(i++ % nok);
if (tmp == null)
throw new AssertionError();
if (exclude != null && tmp.equals(exclude))
throw new AssertionError();
uuids[n++] = tmp;
}
if (INFO)
log.info("Reporting " + uuids.length
+ " under-utilized and non-excluded services: "
+ Arrays.toString(uuids));
return uuids;
}
}