EntityGroupInfo egInfo = entityGroups.get(i); // fetch from head
if (fetchFromTail) {
egInfo = entityGroups.get(entityGroups.size() - 1 - i);
}
i++;
entityGroupsToMove.add(new EntityGroupPlan(egInfo, sal.getServerName(),
null));
numTaken++;
if (numTaken >= numToOffload)
break;
// fetch in alternate order if there is new entityGroup server
if (emptyFServerPresent) {
fetchFromTail = !fetchFromTail;
}
}
serverBalanceInfo.put(sal.getServerName(), new BalanceInfo(numToOffload,
(-1) * numTaken));
}
int totalNumMoved = entityGroupsToMove.size();
// Walk down least loaded, filling each to the min
int neededEntityGroups = 0; // number of entityGroups needed to bring all up to min
fetchFromTail = false;
Map<ServerName, Integer> underloadedServers = new HashMap<ServerName, Integer>();
for (Map.Entry<ServerAndLoad, List<EntityGroupInfo>> server : serversByLoad
.entrySet()) {
int entityGroupCount = server.getKey().getLoad();
if (entityGroupCount >= min) {
break;
}
underloadedServers
.put(server.getKey().getServerName(), min - entityGroupCount);
}
// number of servers that get new entityGroups
int serversUnderloaded = underloadedServers.size();
int incr = 1;
List<ServerName> sns = Arrays.asList(underloadedServers.keySet().toArray(
new ServerName[serversUnderloaded]));
Collections.shuffle(sns, RANDOM);
while (entityGroupsToMove.size() > 0) {
int cnt = 0;
int i = incr > 0 ? 0 : underloadedServers.size() - 1;
for (; i >= 0 && i < underloadedServers.size(); i += incr) {
if (entityGroupsToMove.isEmpty())
break;
ServerName si = sns.get(i);
int numToTake = underloadedServers.get(si);
if (numToTake == 0)
continue;
addEntityGroupPlan(entityGroupsToMove, fetchFromTail, si, entityGroupsToReturn);
if (emptyFServerPresent) {
fetchFromTail = !fetchFromTail;
}
underloadedServers.put(si, numToTake - 1);
cnt++;
BalanceInfo bi = serverBalanceInfo.get(si);
if (bi == null) {
bi = new BalanceInfo(0, 0);
serverBalanceInfo.put(si, bi);
}
bi.setNumEntityGroupsAdded(bi.getNumEntityGroupsAdded() + 1);
}
if (cnt == 0)
break;
// iterates underloadedServers in the other direction
incr = -incr;
}
for (Integer i : underloadedServers.values()) {
// If we still want to take some, increment needed
neededEntityGroups += i;
}
// If none needed to fill all to min and none left to drain all to max,
// we are done
if (neededEntityGroups == 0 && entityGroupsToMove.isEmpty()) {
long endTime = System.currentTimeMillis();
LOG.info("Calculated a load balance in " + (endTime - startTime) + "ms. "
+ "Moving " + totalNumMoved + " entityGroups off of " + serversOverloaded
+ " overloaded servers onto " + serversUnderloaded
+ " less loaded servers");
return entityGroupsToReturn;
}
// Need to do a second pass.
// Either more entityGroups to assign out or servers that are still underloaded
// If we need more to fill min, grab one from each most loaded until enough
if (neededEntityGroups != 0) {
// Walk down most loaded, grabbing one from each until we get enough
for (Map.Entry<ServerAndLoad, List<EntityGroupInfo>> server : serversByLoad
.descendingMap().entrySet()) {
BalanceInfo balanceInfo = serverBalanceInfo.get(server.getKey()
.getServerName());
int idx = balanceInfo == null ? 0 : balanceInfo
.getNextEntityGroupForUnload();
if (idx >= server.getValue().size())
break;
EntityGroupInfo entityGroup = server.getValue().get(idx);
entityGroupsToMove.add(new EntityGroupPlan(entityGroup, server.getKey()
.getServerName(), null));
totalNumMoved++;
if (--neededEntityGroups == 0) {
// No more entityGroups needed, done shedding
break;