package com.dianping.pigeon.remoting.invoker.route.balance; import java.util.List; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.remoting.common.domain.InvocationRequest; import com.dianping.pigeon.remoting.invoker.Client; import com.dianping.pigeon.remoting.invoker.config.InvokerConfig; public class RoundRobinLoadBalance extends AbstractLoadBalance { private static final Logger logger = LoggerLoader.getLogger(RoundRobinLoadBalance.class); public static final String NAME = "roundRobin"; public static final LoadBalance instance = new RoundRobinLoadBalance(); private static int lastSelected = -1; private static int currentWeight = 0; /** * */ @Override protected Client doSelect(List<Client> clients, InvokerConfig<?> invokerConfig, InvocationRequest request, int[] weights) { assert (clients != null && clients.size() > 1); int[] _weights = new int[weights.length - 1]; for (int i = 0; i < weights.length - 1; i++) { _weights[i] = weights[i]; } int clientId = roundRobin(_weights); Client client = clientId < 0 ? clients.get(random.nextInt(_weights.length)) : clients.get(clientId); if (logger.isDebugEnabled()) { logger.debug("select address:" + client.getAddress()); } return client; } public int roundRobin(int[] weights) { int clientSize = weights.length; int gcdWeights = gcdWeights(weights); int maxWeight = maxWeight(weights); if (lastSelected >= clientSize) { lastSelected = clientSize - 1; } while (true) { lastSelected = (lastSelected + 1) % clientSize; if (lastSelected == 0) { currentWeight = currentWeight - gcdWeights; if (currentWeight <= 0) { currentWeight = maxWeight; if (currentWeight == 0) { return -1; } } } if (weights[lastSelected] >= currentWeight) { return lastSelected; } } } private int maxWeight(int[] weights) { int max = weights[0]; for (int it : weights) { if (it > max) { max = it; } } return max; } private int gcdWeights(int[] weights) { return gcdN(weights, weights.length); } private int gcd(int a, int b) { if (0 == b) { return a; } else { return gcd(b, a % b); } } public int gcdN(int[] digits, int length) { if (1 == length) { return digits[0]; } else { return gcd(digits[length - 1], gcdN(digits, length - 1)); } } }