def visit_SNLeaveRequest(self, message): LOGGER.log(logging.DEBUG, "[DGB] SNLeaveRequest - Process") payload_msg = SNLeaveReply(self, self.__local_node) route_msg = RouteDirect(payload_msg, message.leaving_node) self.__local_node.route_internal(route_msg) self.__local_node.neighbourhood.remove_neighbour(message.leaving_node)
def visit_STJoinReply(self, message): ## running on the newborn node, if the welcoming node can welcome us. print("0_0 visit_STJoinReply, phase=", str(message.phase)) if (self.debugging & 2): import pdb pdb.set_trace() if (message.phase == STJoinReply.STATE_PROPOSE): self.__local_node.sign("join proposition received " + str(message.contact_node)) if (self.is_busy(message)): # The local node is already busy with another joining node. join_error = STJoinError( message, "Contacted node already busy with a join activity") self.__local_node.sign("joining and busy!?") route_msg = RouteDirect(join_error, message.joining_node) self.__local_node.route_internal(route_msg) else: self.set_busy(message) print("0_0 adding data in the local store ...") self.__local_node.sign("inserting into local store") # Set data received from contact node. self.__local_node.partition_id = message.partition_id self.__local_node.cpe = message.cpe for data in message.data: self.__local_node.data_store.add(data[0], data[1]) # Send a reply to the contact node. self.__join_msg = STJoinRequest(self.__local_node, STJoinRequest.STATE_ACCEPT) self.__local_node.sign("accepting proposition") route_msg = RouteDirect(self.__join_msg, message.contact_node) self.__local_node.route_internal(route_msg) elif (message.phase == STJoinReply.STATE_CONFIRM): self.set_busy(False) print("0_0 connected, hopefully.") self.__local_node.status = "connected through " + str( message.contact_node) else: join_error = STJoinError(message, "Unrecognized join request.") route_msg = RouteDirect(join_error, message.joining_node) self.__local_node.route_internal(route_msg)
def ping_half_ring(node, half_ring, ring_level): """Send ping to all neighbours (telling them this node is alive).""" neighbours = half_ring.get_neighbours() for neighbour in neighbours: LOGGER.debug("[DBG] Send a Ping to: " + neighbour.__repr__()) payload_msg = SNPingMessage(node, ring_level) route_msg = RouteDirect(payload_msg, neighbour) node.route_internal(route_msg)
def lookupData(self, message): """ expect message ISA LookupRequest """ print(message, " has reached ", self.__local_node) if (self.debugging): import pdb pdb.set_trace() values = self.__local_node.data_store.get(message.key) reply = LookupReply(values, message.nonce) reply.trace = message.trace reply.trace.append("reading data at %s" % self.__local_node.pname) route = RouteDirect(reply, message.originator) self.__local_node.route_internal(route)
def _arrived_at_nearest_node(self, message): """Process a JoinRequest arrived at the nearest node.""" assert message.state == SNJoinRequest.ROUTING # The nearest node's neighbour contains new neighbours for joining node. neighbours = self.__local_node.neighbourhood.get_ring( 0).get_all_unique_neighbours() # Send a reply to the joining node. payload_msg = SNJoinReply(message, neighbours) route_msg = RouteDirect(payload_msg, message.joining_node) self.__local_node.route_internal(route_msg)
def compute_partition_id(self, message, side_join, next_node): ln = self.__local_node partition_id = 0 if (next_node != ln and next_node.cpe.k == 0): ln.sign("%s isn't ready to welcome a new node" % next_node.pname) next_node.queue(RouteDirect(message, ln)) request = RouteDirect(SNPingRequest(ln, 0), next_node) ln.route_internal(request) raise RoutingDeferred("compute_partition_id") # we need to cancel cross-wrap generation of partitionID so that the # rightmost node on the tree is the one with highest PID, leftmost node # is the one with lowest PID and PID monotonously increases in-between. if next_node.partition_id < ln.partition_id and side_join == Direction.RIGHT: ln.sign("RIGHT wrap detected with %s" % next_node.pname) next_node = ln if next_node.partition_id > ln.partition_id and side_join == Direction.LEFT: ln.sign("LEFT wrap detected with %s" % next_node.pname) next_node = ln if (next_node != ln): ln.sign("computing partition for joining node %f<?<%f" % (ln.partition_id, next_node.partition_id)) partition_id = PartitionID.gen_btw(ln.partition_id, next_node.partition_id) else: assert next_node == ln if (side_join == Direction.RIGHT): ln.sign("computing partition for joining node %f<?" % (ln.partition_id)) partition_id = PartitionID.gen_aft(ln.partition_id) else: assert side_join == Direction.LEFT ln.sign("computing partition for joining ?<%f" % ln.partition_id) partition_id = PartitionID.gen_bef(ln.partition_id) assert partition_id != ln.partition_id and partition_id != next_node.partition_id return partition_id
def visit_SNJoinReply(self, message): ln = self.__local_node ng = ln.neighbourhood LOGGER.log(logging.DEBUG, "[DBG] SNJoinReply - Process") if (self.debugging & 4): import pdb pdb.set_trace() ng.sign("repair(%s)" % repr(message)) NeighbourhoodNet.repair_level(ln, ng, 0, message.neightbours) # The contact node for SkipTree is the left or right neighbour. node_left = ng.get_neighbour(Direction.LEFT, 0) node_right = ng.get_neighbour(Direction.RIGHT, 0) psl = ln.name_id.get_longest_prefix_length(node_left.name_id) psr = ln.name_id.get_longest_prefix_length(node_right.name_id) # Launch the SkipTree joining. payload_msg = STJoinRequest(ln, STJoinRequest.STATE_ASK) payload_msg.sign( "%s joint SN. Candidates for ST are %s:%f or %s:%f" % (ln.name_id, node_left.name_id, psl, node_right.name_id, psr)) # decide which neighbour we will join. print("0_0 %s@%f -vs- %s@%f" % (node_left, psl, node_right, psr)) contact_node = node_left if (ng.can_wrap(Direction.LEFT)): contact_node = node_right elif (psl < psr and not ng.can_wrap(Direction.RIGHT)): contact_node = node_right ln.sign("joint the skipnet") payload_msg.sign("prefered %s" % contact_node.name_id) print("0_0 joining the skiptree : %s->%s", ln.name_id, contact_node.name_id) route_msg = RouteDirect(payload_msg, contact_node) ln.route_internal(route_msg)
def by_cpe_get_next_hop_forking(self, lnode, message): self.__lastcall = ['bycpe+f'] dest = [] left, here, right = lnode.cpe.which_side_space(message.space_part, True) if (here): # NOTE: it cannot be 'naked' message, but must be a clone with # search range that has been 'constraint' to stick here. newmsg = copy.copy(message) newmsg.trace = copy.copy(message.trace) newmsg.limit = PidRange(lnode.partition_id, lnode.partition_id) dest.append((lnode, newmsg)) # create 'directions', that identifies sub-rings to be scanned # and the sub-range of PartitionID that should be taken into account. message.sign( "routing %s%s with %s" % ('L' if left else '', 'R' if right else '', repr(message.limit))) directions = list() if (left): r = message.limit.restrict(Direction.RIGHT, lnode.partition_id) directions.append((Direction.LEFT, r, 'L')) if (right): r = message.limit.restrict(Direction.LEFT, lnode.partition_id) directions.append((Direction.RIGHT, r, 'R')) self.__lastcall.append("scanning rings @%s: %s" % (lnode.partition_id, repr(directions))) part = message.space_part neighbourhood = lnode.neighbourhood lastpid, lastngh = None, None # (point) routing guideline: # for a message that must be sent in direction D, we look for # the farthest neighbour that would not reverse the travelling # direction. # (range) routing guideline: # you send a copy to N[i] if region between N[i] and N[i+1] inter- # sects the region you're searching for. for dirx, prange, pd in directions: for height in range(neighbourhood.nb_ring - 1, -1, -1): if height > 0 and neighbourhood.size(dirx, height) < 2: continue # this ring is empty or has a single node. ngh = neighbourhood.get_neighbour(dirx, height) pid = ngh.partition_id if lastngh != None and ngh.name_id == lastngh.name_id: continue # we just checked this neighbour lastngh = ngh self.__lastcall.append("%s (%i, %s)" % (ngh.pname, height, repr(dirx))) if (ngh.cpe.k == 0): ngh.queue(message) reply = RouteDirect(SNPingRequest(lnode, height), ngh) self.__lastcall.append( "requesting routing table complement at %s" % ngh) return [(ngh, reply)] # todo: rate-limit to avoid redundant PING requests. epid = prange.includes_pid( pid) # effective pid = pid+{-1,0,+1} if (epid != None): left, here, right = ngh.cpe.which_side_space(part, True) if (here or RouterReflect.__goes_forward( dirx, left, right)): self.__lastcall.append( "%s is %s compared to %s" % (part, 'here' if here else 'forw', repr(ngh.cpe))) newmsg = copy.copy(message) newmsg.sign("routed to %s at h=%i" % (ngh.pname, height)) newmsg.limit = prange.restrict( Direction.get_opposite(dirx), epid) dest.append((ngh, newmsg)) else: self.__lastcall.append( "ignored w/ %s, %s, %s - %s" % (repr(left), repr(here), repr(right), 'L' if dirx == Direction.LEFT else 'R')) lastpid = pid prange = prange.restrict(dirx, epid) # ^ messages that will be generated after this one will not be allowed # to forward beyond the 'current position'. if (not RouterReflect.__goes_backward(dirx, left, right)): break else: self.__lastcall.append("%f out of partition range %s" % (pid, repr(prange))) # print("0_0 %s : %i"%(repr(message),len(dest))) # ^it's a bad idea to do a per-message report to the MCP. Use your # 'personal log' for that. Otherwise, you're forcing the MCP to do # a poll with period approaching msg_rate x buffer_size or your # own node will stall, waiting for room to appear in STDOUT buffer. return dest
def visit_IdentityRequest(self, message): find_neighbour = IdentityReply(self.__local_node) route_msg = RouteDirect(find_neighbour, message.contact_node) self.__local_node.route_internal(route_msg)
def visit_SNPingRequest(self, message): reply = SNPingMessage(self.__local_node, message.ring_level) reply = RouteDirect(reply, message.source) LOGGER.debug("[DBG] %s -> %s" % (message, reply)) self.__local_node.route_internal(reply)
def visit_STJoinRequest(self, message): # runs in the welcoming node, upon Join Request message. print("0_0 visit_STJoinRequest, phase=", str(message.phase)) if (self.debugging & 1): import pdb pdb.set_trace() ln = self.__local_node if (message.phase == STJoinRequest.STATE_ASK): # A new node would like to join the network. if (self.is_busy(message)): # The local node is already busy with another joining node. join_error = STJoinError( message, "Contacted node already busy with a join activity") ln.sign("sending error message " + join_error) route_msg = RouteDirect(join_error, message.joining_node) ln.route_internal(route_msg) else: # Compute a proposition for the joining node and sent it. self.set_busy(message) ln.status = "welcoming %s" % repr(message.joining_node.name_id) join_side, next_node = self.decide_side_join(message) ln.sign("next on %s is %s" % ("LEFT" if join_side else "RIGHT", repr(next_node))) join_partition_id = self.compute_partition_id( message, join_side, next_node) ln.sign("assigned pid=%f" % join_partition_id) join_cpe, join_data, self.__new_local_cpe, self.__new_local_data =\ self.compute_cpe_and_data(message,join_side) jm = self.__join_msg = STJoinReply(ln, STJoinReply.STATE_PROPOSE) jm.partition_id = join_partition_id jm.cpe = join_cpe jm.data = join_data route_msg = RouteDirect(jm, message.joining_node) ln.sign("sending joinreply (ask phase)") # this message is likely to be large. [network::]OutRequestManager # may have a hard time transmitting this. ln.route_internal(route_msg) ln.sign("sent joinreply (ask phase)") elif (message.phase == STJoinRequest.STATE_ACCEPT): # blindly setup what the other node's compute_data_and_cpe has defined. ln.sign("Update the local node data") ln.cpe = self.__new_local_cpe ln.data_store = DataStore(self.__new_local_data) print("0_0 Data Split accepted") local_node_status = ln.status_updater ln.sign("'repairing' the neighbourhood table") local_node_status.update_status_now() self.set_busy(False) print("0_0 -- Join process completed. --") self.__join_msg = STJoinReply(ln, STJoinReply.STATE_CONFIRM) route_msg = RouteDirect(self.__join_msg, message.joining_node) ln.sign("sending confirmation message") ln.route_internal(route_msg) else: join_error = STJoinError(message, "Unrecognized join request.") ln.sign("sending error message " + join_error) route_msg = RouteDirect(join_error, message.joining_node) ln.route_internal(route_msg)