Пример #1
0
 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()
Пример #2
0
class HashRing:

    # NodeDict (sorted by key): int -> string
    __node_target_dict = None

    # dict: string -> list(int)
    __target_nodes_dict = None

    __change_event = None

    __check_func = None

    __invalid_target_set = None

    __timer = None

    __builded = None

    __destroyed = None

    def __init__(self, check_func, shadow_number=1000):
        self.__change_event = threading.Event()
        self.__change_event.set()
        self.__builded = threading.Event()
        self.__destroyed = threading.Event()
        self.build(check_func, shadow_number)

    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 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 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 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 stop_checking(self):
        if self.__timer:
            self.__timer.cancel()
        self.__timer = None

    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 __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 parse_targets(self, targets):
        target_set = None
        if is_seq(targets):
            target_set = set(targets)
        elif isinstance(targets, str):
            target_set = set([targets])
        else:
            raise HashRingError("The type of parameter 'targets' is UNSUPPORTED! %s" % type(targets))
        return target_set

    def add_targets(self, targets):
        target_set = self.parse_targets(targets)
        for target in target_set:
            self.__add_target(target)

    def remove_targets(self, targets):
        target_set = self.parse_targets(targets)
        for target in target_set:
            self.__remove_target(target)

    def get_target(self, value):
        results = self.get_targets(value, 1)
        if len(results) == 0:
            return None
        else:
            return results[0]

    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