def _get_kbucket_index(self, guid): """ Return the index of the KBucket which is responsible for the given guid. Agrs: guid: The guid for which to find the appropriate KBucket index, as a string or unicode, in hexadecimal Returns: The index of the KBucket responsible for the given guid. Raises: BadGUIDError: The guid was no KBucket's responsibility; an invariant has been violated, or the guid is bad. """ # Since the KBuckets have consecutive ID spaces, # we do a binary search. low, high = 0, len(self._buckets) num_guid = util.guid_to_num(guid) while low < high: mid = low + (high - low) // 2 bucket = self._buckets[mid] if bucket.range_min > num_guid: high = mid elif bucket.range_max <= num_guid: low = mid + 1 else: return mid raise util.BadGUIDError( "No KBucket responsible for guid {0}.".format(guid))
def _get_kbucket_index(self, guid): """ Return the index of the KBucket which is responsible for the given guid. Agrs: guid: The guid for which to find the appropriate KBucket index, as a string or unicode, in hexadecimal Returns: The index of the KBucket responsible for the given guid. Raises: BadGUIDError: The guid was no KBucket's responsibility; an invariant has been violated, or the guid is bad. """ # Since the KBuckets have consecutive ID spaces, # we do a binary search. low, high = 0, len(self._buckets) num_guid = util.guid_to_num(guid) while low < high: mid = low + (high - low) // 2 bucket = self._buckets[mid] if bucket.range_min > num_guid: high = mid elif bucket.range_max <= num_guid: low = mid + 1 else: return mid raise util.BadGUIDError("No KBucket responsible for guid {0}.".format(guid))
def test_guid_to_num(self): test_tuples = ((0, '0000000000000000000000000000000000000000'), (42, '000000000000000000000000000000000000002a'), (2**constants.BIT_NODE_ID_LEN - 1, 'ffffffffffffffffffffffffffffffffffffffff'), (2**constants.BIT_NODE_ID_LEN - 1, 'ffffffffffffffffffffffffffffffffffffffffL'), (2**constants.BIT_NODE_ID_LEN - 1, '0xffffffffffffffffffffffffffffffffffffffffL')) for num, guid in test_tuples: self.assertEqual(util.guid_to_num(guid), num)
def test_add_contact_max_recursion(self): # Add K + 1 contacts that are so close together and to # own_guid, that they force recursive bucket splits. base = util.guid_to_num(self.own_guid) + 1 for i in range(constants.K + 1): self.rt.add_contact( self._make_contact_from_num(base + i) ) # The actual number of KBuckets created is dependend upon K, # so this test will probably break if K changes. In such a case, # please update the test. self.assertEqual(len(self.rt), 157)
def guid_in_range(self, guid): """ Test whether the given guid is in the range of the ID space covered by this KBucket. Args: guid: The guid to test, as a string or unicode, in hexadecimal. Returns: True if `guid` is in this KBucket's range, False otherwise. """ return self.range_min <= util.guid_to_num(guid) < self.range_max
def test_guid_to_num(self): test_tuples = ( (0, '0000000000000000000000000000000000000000'), (42, '000000000000000000000000000000000000002a'), ( 2**constants.BIT_NODE_ID_LEN - 1, 'ffffffffffffffffffffffffffffffffffffffff' ), ( 2**constants.BIT_NODE_ID_LEN - 1, 'ffffffffffffffffffffffffffffffffffffffffL' ), ( 2**constants.BIT_NODE_ID_LEN - 1, '0xffffffffffffffffffffffffffffffffffffffffL' ) ) for num, guid in test_tuples: self.assertEqual(util.guid_to_num(guid), num)
def test_add_new_contact_and_cache(self): # Add K + 1 contacts to initial KBucket, to force a split. base = util.guid_to_num(self.own_guid) + 1 for i in range(constants.K): self.rt.add_contact( self._make_contact_from_num(base + i) ) self.rt.add_contact(self._make_contact_from_num(self.range_max - 1)) # Create a guid that is at maximal distance from own_guid, # thus must be at a different bucket. self.assertEqual(len(self.rt), 2) max_base = (2**constants.BIT_NODE_ID_LEN - 1) ^ self.own_num_guid self.assertTrue(self.rt[0].guid_in_range(self.own_guid)) self.assertTrue(self.rt[1].guid_in_range(util.num_to_guid(max_base))) # Add contacts to the other KBucket, until it is full. for i in range(constants.K): if len(self.rt[1]) == constants.K: break self.rt.add_contact( self._make_contact_from_num(max_base - i) ) # Create and add a contact that is in the range of the other # KBucket. new_contact = self._make_contact_from_num(max_base - constants.K) self.rt.add_contact(new_contact) self.assertEqual( len(self.rt), 2, 'A KBucket not containing own_guid was split.' ) # Assert the new contact was cached properly. self.assertNotIn(new_contact, self.rt[0]) self.assertNotIn(new_contact, self.rt[1]) self.assertEqual([], self.rt[0].get_cached_contacts()) self.assertEqual([new_contact], self.rt[1].get_cached_contacts())