import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.TreeMap;
import java.util.SortedMap;
public class ConsistentHashService {
final private static long ring = 1L << 32;
private int virtualNodeNums = 10;
private HashSet<String> servers;
private TreeMap<Long, String> nodeHashMap;
public ConsistentHashService() {
servers = new HashSet<>();
nodeHashMap = new TreeMap<>();
}
public void setVirtualNodeNum(int nodeNum) {
this.virtualNodeNums = nodeNum;
}
public void addServers(List<String> serverList) {
int serverCount = servers.size();
for(String server : serverList) {
servers.add(server);
}
if(serverCount != servers.size()) {
rebuildVirtualNodes();
}
}
public void removeServers(List<String> serverList) {
int serverCount = servers.size();
for(String server : serverList) {
servers.remove(server);
}
if(serverCount != servers.size()) {
rebuildVirtualNodes();
}
}
public void rebuildVirtualNodes() {
TreeMap<Long, String> newHashMap = new TreeMap<>();
for(String server : servers) {
for(int i = 0; i < virtualNodeNums; i++) {
String v = server + "__VN__" + i;
Long hash = getHash(v) % ring;
newHashMap.put(hash, server);
}
}
nodeHashMap = newHashMap;
}
private Long getHash(String key) {
final int p = 16777619;
Long hash = 2166136261L;
for (int idx = 0, num = key.length(); idx < num; ++idx) {
hash = (hash ^ key.charAt(idx)) * p;
}
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
if (hash < 0) {
hash = Math.abs(hash);
}
return hash;
}
public String getServer(String key) {
Long keyHash = getHash(key) % ring;
SortedMap<Long, String> tailMap = nodeHashMap.tailMap(keyHash);
Long nodeHash = tailMap.isEmpty() ? nodeHashMap.firstKey() : tailMap.firstKey();
return nodeHashMap.get(nodeHash);
}
}
评论