# -*- coding: utf-8 -*-
"""
一致性哈希算法 python实现
参考
/blog//11/27/consistent-hashing
/p/flexihash/
/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]