def update_finger(self, successor, index): if self._finger[index] is not None: if inrange(successor.node_id(), self.node_id() - 1, self._finger[index].node.node_id()): self._finger[index].node = successor # TODO: replace `update_finger` with a RPC call self._predecessor.update_finger(successor, index)
def _closest_preceding_node(self, id): # from m down to 1 for x in reversed(range(len(self._finger))): entry = self._finger[x] # TODO: replace id method with RPC call, maybe a new method to replace _closest_preceding_node if entry != None and entry.node != None and inrange( entry.node.node_id(), self.node_id(), id): return entry.node return self
def find_predecessor(self, id): lg = "find_predecessor of: {}".format(id) self.log(lg) node = self # when the ring only has one node, node.id is the same as node.successor.id, # if we are alone in the ring, we are the pred(id) if node.node_id() == node.successor().node_id(): return node while not inrange(id, node.node_id(), node.successor().node_id() + 1): node = node._closest_preceding_node(id) return node
def find_successor(self, id): print('---------find_successor--------------') self.log("find_successor of {}".format(id)) # if self._predecessor exists, and _predecessor.id < id < self.id, the successor is current node pre_id = self._predecessor.node_id() self_id = self.node_id() if self._predecessor and inrange(id, pre_id, self_id): return self # TODO: replace `find_predecessor` and `successor` with RPC call return self.find_predecessor(id).successor()
def init_finger(self, remote_address=None): if remote_address: # get the arbitrary node in which the target node want to join # TODO: _remote.getRemoteNode _remote with RPC client # remote_node = self._remote.getRemoteNode(remote_address) remote_node = self.get_remote_node(remote_address) # first find its successor, i.e. the first entry in its finger table successor = self.successor() if successor is None: # TODO: replace with RPC call find_succ successor = remote_node.find_successor(self.node_id()) self._successor = successor # initialize the rest of its finger table for x in range(1, M_BIT): start_id = (self.node_id() + 2**x) % NUM_SLOTS self._finger[x] = FingerEntry(start_id, None) # find the corresponding nodes that are supposed to be in the finger table for x in range(0, M_BIT - 1): start_id = self._finger[x + 1].start if inrange(start_id, self.node_id(), self._finger[x].node.node_id()): # if inrange, no RPC call needed, assign locally self._finger[x + 1].node = self._finger[x].node else: """ need to call find successor leveraging finger table for `self.find_successor`, if its the first node """ successor = self.find_successor(start_id) self._finger[x + 1] = FingerEntry(start_id, successor) else: # n is the only node in the network for x in range(0, M_BIT): start_id = math.floor((self.node_id() + 2**x) % NUM_SLOTS) self._finger[x] = FingerEntry(start_id, self) self.print_finger('init_finger')
def stabilize(self): if self._leave: return # prevent successor failure successor = self.successor() # pre = successor._predecessor pre = successor.predecessor() print('-----------stabilize--------------') pre_id = pre.node_id() self_id = self.node_id() succ_id = successor.node_id() if pre is not None and inrange(pre_id, self_id, succ_id): self.log('stabilize calls update_successor') self.update_successor(pre) print('stabilize successor: ', successor.notify) successor.notify(self) self.print_finger('stabilize') threading.Timer(2, self.stabilize).start()
def exposed_notify(self, pre): # check if pre is the new predecessor if (self._predecessor is None or inrange(pre.node_id(), self._predecessor.node_id(), self.node_id())): self._predecessor = pre