package org.zstack.utils.hash;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import java.util.*;
public class ConsistentHash<T> {
private final CLogger logger = Utils.getLogger(ConsistentHash.class);
private final HashFunction hashFunction;
private final int numberOfReplicas;
private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>();
private final Set<T> nodes = new HashSet<T>();
public ConsistentHash(HashFunction hashFunction, int numberOfReplicas,
Collection<T> nodes) {
this.hashFunction = hashFunction;
this.numberOfReplicas = numberOfReplicas;
for (T node : nodes) {
add(node);
}
}
public Set<T> getNodes() {
return nodes;
}
public void add(T node) {
nodes.add(node);
for (int i = 0; i < numberOfReplicas; i++) {
String nodeName = node.toString() + i;
circle.put(hashFunction.hash(nodeName), node);
}
logger.debug(String.format("after adding, consistent hash circle has management nodes%s, %s virtual nodes now",
nodes, circle.size()));
}
public void remove(T node) {
nodes.remove(node);
logger.debug(String.format("the consistent hash ring currently has nodes%s", nodes));
for (int i = 0; i < numberOfReplicas; i++) {
String nodeName = node.toString() + i;
circle.remove(hashFunction.hash(nodeName));
}
logger.debug(String.format("after removing, consistent hash circle has management nodes%s, %s virtual nodes now",
nodes, circle.size()));
}
public boolean hasNode(T node) {
for (int i = 0; i < numberOfReplicas; i++) {
String nodeName = node.toString() + i;
if (circle.containsKey(hashFunction.hash(nodeName))) {
return true;
}
}
return false;
}
public T get(Object key) {
if (circle.isEmpty()) {
return null;
}
int hash = hashFunction.hash(key);
if (!circle.containsKey(hash)) {
SortedMap<Integer, T> tailMap = circle.tailMap(hash);
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}
return circle.get(hash);
}
}