def _stabilize(self): "Periodically verify node's inmediate succesor and tell the successor about it" # if successor fails find first alive successor in the # successor list if not self.is_node_alive(self.successor): self.successor = self.find_first_successor_alive() log.debug( f'set new succesor from successor list: {self.successor.id}') try: with self.proxy(self.successor) as remote: node = remote.predecessor if node and self.is_node_alive(node) and in_interval_r( node.id, self.id, self.successor.id): self.successor = node log.debug(f'finded new succesor: {node.id}') self._update_successor_list() except BaseException as why: pass try: with self.proxy(self.successor) as remote: remote.notify(self.info) except Pyro4.errors.ConnectionClosedError: # between remote._update_successor_list remote fails and this is fixed when this method is called again, so i just let ignore this exception for efficiency pass
def print_info(self): log.debug(f''' suc: {self.successor.id if self.successor else None} pred: {self.predecessor.id if self.predecessor else None} s_list: { list(map(lambda node: node.id if node else None,self.successor_list))} finger: {self.finger.print_fingers()} keys: {list(map(lambda i:i[0],self.data.items()))} assured: {list(map(lambda i:i[0],self.assured_data.items()))}''')
def __init__(self, id, ip, port, chord_id: str = 'default'): self.id = id self.ip = ip self.port = port self.finger = FingerTable(self.id) self.data = {} self._successor_list = [None for _ in range(m)] self.assured_data = {} self.chord_id = chord_id log.init_logger(f"Node {self.id}", log.INFO) # init logging log.debug(f"init")
def inner(*args, **kwargs): for i in range(attempts): try: result = func(*args, **kwargs) except BaseException as error: log.error( f'retry {i+1}/{attempts} {func.__name__}: {error}') time.sleep(retry_delay) continue if i > 0: log.debug( f'resolve correctly function: {func.__name__} in attemt {i}' ) return result log.exception(f"can't handle exceptions with stabilization") args[0].print_info()
def notify(self, node: 'NodeInfo'): "Node think is might be our predecessor" if not self.predecessor or not self.is_node_alive( self.predecessor) or in_interval(node.id, self.predecessor.id, self.id): self.predecessor = node log.debug(f'set new predecessor: {node.id}') # Take dada from storage is needed for key in list(self.assured_data.keys()): if in_interval(key, self.predecessor.id, self.id): value, t = self.assured_data.pop(key) self.data[key] = value log.debug(f'assume key assured : {key}') # Transfer data to predecessor transference = {} for key in list(self.data.keys()): # this interval is all the rign except this node # interval, is different of key < predecessor.id # because the rign is circular if in_interval(key, self.id, self.predecessor.id): transference[key] = self.data.pop(key) # send data to predecessor node try: with self.proxy(self.predecessor) as remote: remote.set_data(transference) log.debug( f'set data to predecessor (node {self.predecessor.id}): {list(transference.keys())}' ) except BaseException: log.exception( f'problem sending data to node {self.predecessor.id}') # remerge data again into this node data self.data = {**self.data, **transference}
def join(self, node: 'NodeInfo'): "node self joins the network node is a arbitrary node in the network" self.predecessor = None log.debug('joint') with self.proxy(node) as remote: self.successor = remote.find_successor(self.id) # initialize successor_list using successor.successor_list log.debug(f'finded successor: {self.successor.id}') self._update_successor_list() log.debug(f"join to {node.id} succesfuly")
def delete(self, key): log.debug(f"call delete key {key}") node = self.find_successor(key) with self.proxy(node) as remote: return remote.delete_item(key)
def load(self, key): log.debug(f"call load key {key}") node = self.find_successor(key) with self.proxy(node) as remote: return remote.get_item(key)
def save(self, key: int, value): log.debug(f"call save key: {key}") node = self.find_successor(key) with self.proxy(node) as remote: remote.set_item(key, value)
def __del__(self): self.pyro_daemon.close() log.debug('shutdown')