package netflix.ocelli.loadbalancer; import netflix.ocelli.LoadBalancerStrategy; import netflix.ocelli.loadbalancer.weighting.ClientsAndWeights; import netflix.ocelli.loadbalancer.weighting.WeightingStrategy; import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; import java.util.Random; /** * Select the next element using a random number. * * The weights are sorted such as that each cell in the array represents the * sum of the previous weights plus its weight. This structure makes it * possible to do a simple binary search using a random number from 0 to * total weights. * * Runtime complexity is O(log N) * * @author elandau * */ public class RandomWeightedLoadBalancer<T> implements LoadBalancerStrategy<T> { public static <T> RandomWeightedLoadBalancer<T> create(final WeightingStrategy<T> strategy) { return new RandomWeightedLoadBalancer<T>(strategy); } private final WeightingStrategy<T> strategy; private final Random rand = new Random(); public RandomWeightedLoadBalancer(final WeightingStrategy<T> strategy) { this.strategy = strategy; } /** * @throws NoSuchElementException */ @Override public T choose(List<T> local) { final ClientsAndWeights<T> caw = strategy.call(local); if (caw.isEmpty()) { throw new NoSuchElementException("No servers available in the load balancer"); } int total = caw.getTotalWeights(); if (total == 0) { return caw.getClient(rand.nextInt(caw.size())); } int pos = Collections.binarySearch(caw.getWeights(), rand.nextInt(total)); return caw.getClient(pos >= 0? pos+1 : -pos - 1); } }