package com.alibaba.doris.algorithm;
import java.util.Collection;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
/**
*
* ConsistentHashRouteAlglorithm
* @author Kun He (Raymond He), kun.hek@alibaba-inc.com
* @since 1.0 2011-5-10
*/
public class ConsistentHashRouteAlglorithm implements RouteAlgorithm {
private HashFunction hashFunction;
private int numberOfReplicas;
private int nodeCount;
private Collection<Integer> nodes;
private SortedMap<Integer, Integer> circle = new TreeMap<Integer, Integer>();
private Properties configProperties;
public static final String _Route_ConsistentHashReplicas = "route.consistenthash.replicas";
public static final String _Route_ConsistentHashNodeCount = "route.consistenthash.nodecount";
public ConsistentHashRouteAlglorithm() {
}
public ConsistentHashRouteAlglorithm(HashFunction hashFunction, int numberOfReplicas,
Collection<Integer> nodes) {
this.hashFunction = hashFunction;
this.numberOfReplicas = numberOfReplicas;
this.nodes = nodes;
}
public void setConfigProperties(Properties properties) {
this.configProperties = properties;
}
public void setNumberOfReplicas(int numberOfReplicas) {
this.numberOfReplicas = numberOfReplicas;
}
public void setNodeCount(int nodeCount) {
this.nodeCount = nodeCount;
}
public void addNode(Integer node) {
for (int i = 0; i < numberOfReplicas; i++) {
circle.put(hashFunction.hash(node.toString() + i), node);
}
}
public void removeNode(Integer node) {
for (int i = 0; i < numberOfReplicas; i++) {
circle.remove(hashFunction.hash(node.toString() + i));
}
}
public Integer getNodeByKey(String key) {
if (circle.isEmpty()) {
return null;
}
int hash = hashFunction.hash(key);
if (!circle.containsKey(hash)) {
SortedMap<Integer, Integer> tailMap = circle.tailMap(hash);
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}
return circle.get(hash);
}
/**
* @param nodes
*/
@SuppressWarnings("unchecked")
public void initConfig() {
//_Route_hashfunction_class
String hashFunctionClassName = configProperties.getProperty( RouteAlgorithm._Route_hashfunction_class );
Class<? extends HashFunction> hashFunctionClass;
if( hashFunctionClassName == null) {
hashFunctionClassName = KetamaHashFunction.class.getName();
}
//hashFunctionClassName
try {
hashFunctionClass = (Class<? extends HashFunction>) Thread.currentThread().getContextClassLoader().loadClass( hashFunctionClassName );
hashFunction = hashFunctionClass.newInstance();
} catch (Exception e1) {
throw new IllegalArgumentException("Invalid property '" + RouteAlgorithm._Route_hashfunction_class +"' " + hashFunctionClassName +". Cause: " + e1.getMessage());
}
try {
numberOfReplicas = Integer.valueOf(configProperties.getProperty( _Route_ConsistentHashReplicas ));
}catch(Exception e) {
throw new IllegalArgumentException("Invalid property '" + _Route_ConsistentHashReplicas +"' " + configProperties.getProperty( _Route_ConsistentHashReplicas ) + ". It must be a integer.");
}
//init nodes.
init();
}
/**
*
*/
public void init() {
if( hashFunction == null)
hashFunction = new KetamaHashFunction();
for (int i = 0; i < nodeCount; i++) {
Integer node = Integer.valueOf(i);
addNode(node);
}
}
public Integer getVirtualByKey(String key) {
// TODO Auto-generated method stub
return null;
}
}