class ConsistentHasher: def __init__(self): self.nodes = BST() self.id_to_node = dict() def hash(self, item, limit=4294967295): id_hash = hashlib.sha512(item.encode()) id_hash_int = int.from_bytes(id_hash.digest(), 'big') final_id = id_hash_int % limit return final_id def add_node(self, node_name): hash_id = self.hash(node_name) self.nodes.insert(hash_id) self.id_to_node[hash_id] = node_name def remove_node(self, node_name): hash_id = self.hash(node_name) removed = self.nodes.remove(hash_id) print('Removed %s: %r' % (node_name, removed)) return self.id_to_node.pop(hash_id, None) def assign_key_to_node(self, key): key_hash_id = self.hash(key) assigned_node_id = self.nodes.find_next_bigger_elem(key_hash_id) if assigned_node_id is None: print('Failed to assign key %s (hash = %d) to any node!' % (key, key_hash_id)) return # print('Key %s was hashed to value %d, and was assigned to node %s with id %d' % (key, key_hash_id, self.id_to_node[assigned_node_id], assigned_node_id)) return self.id_to_node[assigned_node_id]
def test_bst(self): numbers = [10, 15, 3, 6, 12, 20, 1, 0] bst = BST() for num in numbers: bst.insert(num) ordered_nums = bst.traverse_inorder() print(ordered_nums) for num in numbers: successor = bst.find_next_bigger_elem(num) if successor is not None: print('Successor of %d is %d' % (num, successor)) else: print('Successor of %d is %s' % (num, 'None')) predecessor = bst.find_previous_smaller_elem(num) if predecessor is not None: print('Predecessor of %d is %d' % (num, predecessor)) else: print('Predecessor of %d is %s' % (num, 'None')) print('\n') num = -1 # Does not exist in the list successor = bst.find_next_bigger_elem(num) if successor is not None: print('Successor of %d is %d' % (num, successor)) else: print('Successor of %d is %s' % (num, 'None')) print('\n') num = 1 removed = bst.remove(num) if removed is not None: print('%d removed from tree: %s' % (num, " ".join(str(x) for x in bst.traverse_inorder()))) else: print('%d was not found in the tree' % num)
class ConsistentHasher: def __init__(self): self.nodes = BST() self.id_to_node = dict() # Note: we need a deterministic hash function. Python hashlib's hash() is not deterministic, and will return # a different hash value on different runs. def hash(self, item, limit=4294967295): id_hash = hashlib.sha512(item.encode()) id_hash_int = int.from_bytes( id_hash.digest(), 'big' ) # Uses explicit byteorder for system-agnostic reproducibility final_id = id_hash_int % limit return final_id def hash2(self, item): return zlib.adler32(str.encode(item)) & 0xffffffff def add_node(self, node_name): hash_id = self.hash(node_name) self.nodes.insert(hash_id) self.id_to_node[hash_id] = node_name def remove_node(self, node_name): hash_id = self.hash(node_name) removed = self.nodes.remove(hash_id) print('Removed %s: %r' % (node_name, removed)) return self.id_to_node.pop(hash_id, None) def assign_key_to_node(self, key): key_hash_id = self.hash(key) assigned_node_id = self.nodes.find_next_bigger_elem(key_hash_id) if assigned_node_id is None: print('Failed to assign key %s (hash = %d) to any node!' % (key, key_hash_id)) return # print('Key %s was hashed to value %d, and was assigned to node %s with id %d' % (key, key_hash_id, self.id_to_node[assigned_node_id], assigned_node_id)) return self.id_to_node[assigned_node_id]