class ConsistHash(object): def __init__(self, size=0xffff): self.size = size # set consistent hash circul size self.rbt = RBTree() # red black tree def insert_host(self, host): host_id = host.get_id(self.size) self.rbt.insert(host_id, host) def remove_host(self, host): host_id = host.get_id(self.size) self.rbt.remove(host_id) @staticmethod def _find_upper(root, elem): if root is None: return -1 if elem == root.key: return root.key elif elem < root.key: maybe_max = find_upper(root.left, elem) if _not_exists(maybe_max): return root.key return maybe_max else: maybe_max = find_upper(root.right, elem) if _not_exists(maybe_max): return -1 return maybe_max def find_host(self, id): id %= self.size idx = self._find_upper(self.rbt._root, id) if idx == -1: # id larger than max id # assert tree is not empty return self.rbt.min_item()[1] return self.rbt.get_value(idx)
class ExponentiallyDecayingSample(object): RESCALE_THRESHOLD = 60 * 60 def __init__(self, reservoir_size, alpha): self.values = RBTree() self.counter = Atomic(0) self.next_scale_time = Atomic(0) self.alpha = alpha self.reservoir_size = reservoir_size self.lock = RLock() self.clear() def clear(self): with self.lock: self.values.clear() self.counter.value = 0 self.next_scale_time.value = time() + self.RESCALE_THRESHOLD self.start_time = time() def size(self): count = self.counter.value if count < self.reservoir_size: return count return self.reservoir_size def __len__(self): return self.size() def snapshot(self): with self.lock: return Snapshot(list(self.values.values())) def weight(self, timestamp): return math.exp(self.alpha * timestamp) def rescale(self, now, next_time): if self.next_scale_time.compare_and_swap(next_time, now + self.RESCALE_THRESHOLD): with self.lock: old_start_time = self.start_time self.start_time = time() for key in list(self.values.keys()): value = self.values.remove(key) self.values[key * math.exp(-self.alpha * (self.start_time - old_start_time))] = value def update(self, value, timestamp=None): if not timestamp: timestamp = time() with self.lock: try: priority = self.weight(timestamp - self.start_time) / random.random() except OverflowError: priority = sys.float_info.max new_count = self.counter.update(lambda v: v + 1) if math.isnan(priority): return if new_count <= self.reservoir_size: self.values[priority] = value else: first_priority = self.values.root.key if first_priority < priority: if priority in self.values: self.values[priority] = value if not self.values.remove(first_priority): first_priority = self.values.root()
class ExponentiallyDecayingSample(object): RESCALE_THRESHOLD = 60 * 60 def __init__(self, reservoir_size, alpha): self.values = RBTree() self.counter = Atomic(0) self.next_scale_time = Atomic(0) self.alpha = alpha self.reservoir_size = reservoir_size self.lock = RLock() self.clear() def clear(self): with self.lock: self.values.clear() self.counter.value = 0 self.next_scale_time.value = time() + self.RESCALE_THRESHOLD self.start_time = time() def size(self): count = self.counter.value if count < self.reservoir_size: return count return self.reservoir_size def __len__(self): return self.size() def snapshot(self): with self.lock: return Snapshot(list(self.values.values())) def weight(self, timestamp): return math.exp(self.alpha * timestamp) def rescale(self, now, next_time): if self.next_scale_time.compare_and_swap(next_time, now + self.RESCALE_THRESHOLD): with self.lock: old_start_time = self.start_time self.start_time = time() for key in list(self.values.keys()): value = self.values.remove(key) self.values[key * math.exp( -self.alpha * (self.start_time - old_start_time))] = value def update(self, value, timestamp=None): if not timestamp: timestamp = time() with self.lock: try: priority = self.weight(timestamp - self.start_time) / random.random() except OverflowError: priority = sys.float_info.max new_count = self.counter.update(lambda v: v + 1) if math.isnan(priority): return if new_count <= self.reservoir_size: self.values[priority] = value else: first_priority = self.values.root.key if first_priority < priority: if priority in self.values: self.values[priority] = value if not self.values.remove(first_priority): first_priority = self.values.root()