一致性哈希算法 python实现

Posted on 2013-01-17 12:03  蛇小狼  阅读(1031)  评论(0编辑  收藏  举报
# -*- coding: utf-8 -*-

"""
一致性哈希算法 python实现
参考
http://weblogs.java.net/blog/2007/11/27/consistent-hashing
http://code.google.com/p/flexihash/
http://www.codinglabs.org/html/consistent-hashing.html
"""

import hashlib


class ConsistentHash(object):

    def __init__(self, hasher=None, replicas=None):
        self.hasher = hasher and hasher or hashlib.md5
        self.replicas = replicas and replicas or 64
        self.positionToTarget = {}
        self.targetToPositions = {}
        self.targetCount = 0


    def addTarget(self, target): 
        self.targetToPositions[target] = []
    
        for i in range(self.replicas):
            position = self.hasher(str(target)+str(i)).hexdigest()
            self.positionToTarget[position] = target
            self.targetToPositions[target].append(position)
        
        self.targetCount += 1

    def addTargets(self, targets):
        for target in targets:
            self.addTarget(target)

    def removeTarget(self, target):
        if self.targetToPositions.has_key(target):
            for position in self.targetToPositions[target]:
                self.positionToTarget.pop(position)

            self.targetToPositions.pop(target)
            self.targetCount -= 1

    def getAllTargets(self):
        return self.targetToPositions.keys()

    def lookupList(self, resource, requestedCount):
        if not self.positionToTarget:
            return []

        resourcePosition = self.hasher(resource).hexdigest()
        results = []
        collect = False

        for key in sorted(self.positionToTarget.keys()):
            value = self.positionToTarget[key]
            if not collect and key > resourcePosition:
                collect = True

            if collect and value not in results:
                results.append(value)

            if len(results) == requestedCount or \
                len(results) == self.targetCount:
                return results


        for key in sorted(self.positionToTarget.keys()):
            value = self.positionToTarget[key]

            if value not in results:
                results.append(value)

            if len(results) == requestedCount or \
                len(results) == self.targetCount:
                return results

        return results

    def lookup(self, resource):
        targets = self.lookupList(resource, 1)
        return targets[0]