def transferKeyValues(self, node): """ Given a new node, send it all the keys/values it should be storing. @param node: A new node that just joined (or that we just found out about). Process: For each key in storage, get k closest nodes. If newnode is closer than the furtherst in that list, and the node for this server is closer than the closest in that list, then store the key/value on the new node (per section 2.5 of the paper) """ def send_values(inv_list): values = [] if inv_list[0]: for requested_inv in inv_list[1]: try: i = objects.Inv() i.ParseFromString(requested_inv) value = self.storage.getSpecific(i.keyword, i.valueKey) if value is not None: v = objects.Value() v.keyword = i.keyword v.valueKey = i.valueKey v.serializedData = value v.ttl = int(round(self.storage.get_ttl(i.keyword, i.valueKey))) values.append(v.SerializeToString()) except Exception: pass if len(values) > 0: self.callValues(node, values) inv = [] for keyword in self.storage.iterkeys(): keyword = keyword[0].decode("hex") keynode = Node(keyword) neighbors = self.router.findNeighbors(keynode, exclude=node) if len(neighbors) > 0: newNodeClose = node.distanceTo(keynode) < neighbors[-1].distanceTo(keynode) thisNodeClosest = self.sourceNode.distanceTo(keynode) < neighbors[0].distanceTo(keynode) if len(neighbors) == 0 \ or (newNodeClose and thisNodeClosest) \ or (thisNodeClosest and len(neighbors) < self.ksize): # pylint: disable=W0612 for k, v in self.storage.iteritems(keyword): i = objects.Inv() i.keyword = keyword i.valueKey = k inv.append(i.SerializeToString()) if len(inv) > 100: random.shuffle(inv) if len(inv) > 0: self.callInv(node, inv[:100]).addCallback(send_values)
def rpc_inv(self, sender, *serlialized_invs): self.addToRouter(sender) ret = [] for inv in serlialized_invs: try: i = objects.Inv() i.ParseFromString(inv) if self.storage.getSpecific(i.keyword, i.valueKey) is None: ret.append(inv) except Exception: pass return ret
def test_transferKeyValues(self): self._connecting_to_connected() self.wire_protocol[self.addr1] = self.con self.protocol.storage[digest("keyword")] = ( digest("key"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.protocol.storage[digest("keyword")] = ( digest("key2"), self.protocol.sourceNode.getProto().SerializeToString(), 10) self.protocol.transferKeyValues( Node(digest("id"), self.addr1[0], self.addr1[1])) self.clock.advance(1) connection.REACTOR.runUntilCurrent() sent_packet = packet.Packet.from_bytes( self.proto_mock.send_datagram.call_args_list[0][0][0]) sent_message = sent_packet.payload x = message.Message() x.ParseFromString(sent_message) i = objects.Inv() i.keyword = digest("keyword") i.valueKey = digest("key") i2 = objects.Inv() i2.keyword = digest("keyword") i2.valueKey = digest("key2") m = message.Message() m.sender.MergeFrom(self.protocol.sourceNode.getProto()) m.command = message.Command.Value("INV") m.protoVer = self.version m.arguments.append(i.SerializeToString()) m.arguments.append(i2.SerializeToString()) self.assertEqual(x.sender.guid, m.sender.guid) self.assertEqual(x.command, m.command) self.assertTrue(x.arguments[0] in m.arguments) self.assertTrue(x.arguments[1] in m.arguments)
def send_values(inv_list): values = [] if inv_list[0]: for requested_inv in inv_list[1]: try: i = objects.Inv() i.ParseFromString(requested_inv) value = self.storage.getSpecific(i.keyword, i.valueKey) if value is not None: v = objects.Value() v.keyword = i.keyword v.valueKey = i.valueKey v.serializedData = value v.ttl = int(round(self.storage.get_ttl(i.keyword, i.valueKey))) values.append(v.SerializeToString()) except Exception: pass if len(values) > 0: self.callValues(node, values)