/* * Copyright (c) 2014 Globo.com - ATeam * All rights reserved. * * This source is subject to the Apache License, Version 2.0. * Please see the LICENSE file for more information. * * Authors: See AUTHORS file * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.globo.galeb.consistenthash; import java.util.Collection; import java.util.SortedMap; import java.util.TreeMap; /** * Class ConsistentHash. * * @param <T> the generic type of node * @author: See AUTHORS file. * @version: 1.0.0, 19/10/2014. */ public class ConsistentHash<T> { /** The {@link HashAlgorithm Hash Algorithm} */ private HashAlgorithm hashAlgorithm; /** The number of replicas. */ private int numberOfReplicas; /** The circle. */ private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>(); /** * Instantiates a new consistent hash. * * @param hashAlgorithm The {@link HashAlgorithm Hash Algorithm} * @param numberOfReplicas the number of replicas * @param nodes nodes collection */ public ConsistentHash(HashAlgorithm hashAlgorithm, int numberOfReplicas, Collection<T> nodes) { this.hashAlgorithm = hashAlgorithm; this.numberOfReplicas = numberOfReplicas; for (T node : nodes) { add(node); } } /** * Adds a node. * * @param node a node */ public void add(T node) { for (int i = 0; i < numberOfReplicas; i++) { circle.put(hashAlgorithm.hash(node.toString() + i).asInt(), node); } } /** * Removes a node. * * @param node a node */ public void remove(T node) { for (int i = 0; i < numberOfReplicas; i++) { circle.remove(hashAlgorithm.hash(node.toString() + i).asInt()); } } /** * Gets a node. * * @param key a key * @return a node from cicle */ public T get(String key) { if (circle.isEmpty()) { return null; } int hash= hashAlgorithm.hash(key).asInt(); if (!circle.containsKey(hash)) { SortedMap<Integer, T> tailMap = circle.tailMap(hash); hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey(); } return circle.get(hash); } /** * Rebuild the cicle. * * @param hashAlgorithm The {@link HashAlgorithm Hash Algorithm} * @param numberOfReplicas the number of replicas * @param nodes nodes collection */ public void rebuild(HashAlgorithm hashAlgorithm, Integer numberOfReplicas, Collection<T> nodes) { if (hashAlgorithm!=null) { this.hashAlgorithm = hashAlgorithm; } if (numberOfReplicas!=null) { this.numberOfReplicas = numberOfReplicas; } circle.clear(); for (T node : nodes) { add(node); } } }