def start_checking(self): if not self.__check_func: get_logger().info("The check function is None. IGNORE the checking operation.") else: if not self.__timer: self.__invalid_target_set = set([]) self.__timer = RepeatTimer(2, self.check) get_logger().info("Starting node checking timer...") self.__timer.start()
def __remove_target(self, target): self.__change_event.wait() self.__change_event.clear() try: if self.__node_target_dict: invalid_node_target_dict = {k:v for k, v in self.__node_target_dict.items() if v == target} self.__node_target_dict.delete(invalid_node_target_dict) if self.__target_nodes_dict: if target in self.__target_nodes_dict: del self.__target_nodes_dict[target] get_logger().info("The target '{0}' is removed successfully.".format(target)) finally: self.__change_event.set()
def destroy(self): if self.__destroyed.isSet(): get_logger().info("The hash ring has been destroyed. IGNORE the destroy operation.") return self.__change_event.wait() self.__change_event.clear() try: self.__destroyed.set() self.stop_checking() self.__node_target_dict = None self.__target_nodes_dict = None self.__builded.clear() get_logger().info("The hash ring is destroyed.") finally: self.__change_event.set()
def __add_target(self, target): self.__change_event.wait() self.__change_event.clear() try: target_shadows = [] target_nodes = [] current_node_target_dict = {} for i in range(0, self._shadow_number): target_shadows.append("%s-%s" % (target, i)) for target_shadow in target_shadows: numbers = get_ketama_numbers(target_shadow) for number in numbers: current_node_target_dict[number] = target target_nodes.append(number) self.__target_nodes_dict[target] = target_nodes self.__node_target_dict.update(current_node_target_dict) get_logger().info("The target '{0}' is added successfully. The number of node: {1}.".format(target, len(target_nodes))) get_logger().debug("The nodes of target '{0}' is {1}.".format(target, target_nodes)) finally: self.__change_event.set()
def check(self): if not self.__check_func: get_logger().debug("The check function is None. IGNORE checking.") return get_logger().debug("Checking nodes in hash ring...") self.__change_event.wait() targets = self.__target_nodes_dict.keys() for t in targets: result = self.__check_func(t) if not result: get_logger().info("The target '{0}' is INVALID. Delete it from hash ring.".format(t)) self.__remove_target(t) self.__invalid_target_set = self.__invalid_target_set | set([t]) get_logger().debug("Checking the nodes which have been added but invalid...") for it in self.__invalid_target_set: result = self.__check_func(it) if result: get_logger().info("The invalid target '{0}' is OK. Add it to hash ring.".format(it)) self.__add_target(it) self.__invalid_target_set = self.__invalid_target_set - set([it])
def build(self, check_func, shadow_number=1000): if self.__builded.isSet(): get_logger().info("Please destroy hash ring before rebuilding.") return self.__change_event.wait() self.__change_event.clear() try: self.__builded.set() self.__check_func = check_func if shadow_number > 0: self._shadow_number = shadow_number else: self._shadow_number = 1000 self.__node_target_dict = NodeDict() self.__target_nodes_dict = {} self.start_checking() self.__destroyed.clear() get_logger().info("The hash ring is builded.") finally: self.__change_event.set()
def get_targets(self, value, number): results = [] if not value: return results if number <= 0: number = 1 self.__change_event.wait() target_number = len(self.__target_nodes_dict) if number > target_number: number = target_number h = get_hash_for_key(str(value)) currentHash = h while len(results) < number: node = self.__node_target_dict.to_node(currentHash) if node in self.__node_target_dict: target = self.__node_target_dict[node] if target not in results: results.append(target) currentHash = node + 1 get_logger().debug("The targets of key '{0}' ({1}) is {2}.".format(value, h, results)) return results