public void NonRespondingContactDelayedEvictionTest()
        {
            // Create a DHT so we have an eviction handler.
            Dht dht = new Dht(ID.Zero, new VirtualProtocol(), () => null, new Router());
            //Contact dummyContact = new Contact(new VirtualProtocol(), ID.Zero);
            //((VirtualProtocol)dummyContact.Protocol).Node = new Node(dummyContact, new VirtualStorage());

            IBucketList bucketList = SetupSplitFailure(dht.Node.BucketList);

            Assert.IsTrue(bucketList.Buckets.Count == 2, "Bucket split should have occurred.");
            Assert.IsTrue(bucketList.Buckets[0].Contacts.Count == 1, "Expected 1 contact in bucket 0.");
            Assert.IsTrue(bucketList.Buckets[1].Contacts.Count == 20, "Expected 20 contacts in bucket 1.");

            // The bucket is now full.  Pick the first contact, as it is last seen (they are added in chronological order.)
            Contact nonRespondingContact = bucketList.Buckets[1].Contacts[0];

            // Since the protocols are shared, we need to assign a unique protocol for this node for testing.
            VirtualProtocol vpUnresponding = new VirtualProtocol(((VirtualProtocol)nonRespondingContact.Protocol).Node, false);

            nonRespondingContact.Protocol = vpUnresponding;

            // Setup the next new contact (it can respond.)
            Contact nextNewContact = new Contact(dht.Contact.Protocol, ID.Zero.SetBit(159));

            bucketList.AddContact(nextNewContact);

            Assert.IsTrue(bucketList.Buckets[1].Contacts.Count == 20, "Expected 20 contacts in bucket 1.");

            // Verify CanSplit -> Evict happened.

            Assert.IsTrue(dht.PendingContacts.Count == 1, "Expected one pending contact.");
            Assert.IsTrue(dht.PendingContacts.Contains(nextNewContact), "Expected pending contact to be the 21st contact.");
            Assert.IsTrue(dht.EvictionCount.Count == 1, "Expected one contact to be pending eviction.");
        }
        public void ForceFailedAddTest()
        {
            Contact dummyContact = new Contact(new VirtualProtocol(), ID.Zero);

            ((VirtualProtocol)dummyContact.Protocol).Node = new Node(dummyContact, new VirtualStorage());

            IBucketList bucketList = SetupSplitFailure();

            Assert.IsTrue(bucketList.Buckets.Count == 2, "Bucket split should have occurred.");
            Assert.IsTrue(bucketList.Buckets[0].Contacts.Count == 1, "Expected 1 contact in bucket 0.");
            Assert.IsTrue(bucketList.Buckets[1].Contacts.Count == 20, "Expected 20 contacts in bucket 1.");

            // This next contact should not split the bucket as depth == 5 and therefore adding the contact will fail.
            // Any unique ID >= 2^159 will do.
            byte[] id = new byte[20];
            id[19] = 0x80;
            Contact newContact = new Contact(dummyContact.Protocol, new ID(id));

            bucketList.AddContact(newContact);

            Assert.IsTrue(bucketList.Buckets.Count == 2, "Bucket split should not have occurred.");
            Assert.IsTrue(bucketList.Buckets[0].Contacts.Count == 1, "Expected 1 contact in bucket 0.");
            Assert.IsTrue(bucketList.Buckets[1].Contacts.Count == 20, "Expected 20 contacts in bucket 1.");

            // Verify CanSplit -> Evict did not happen.
            Assert.IsFalse(bucketList.Buckets[1].Contacts.Contains(newContact), "Expected new contact NOT to replace an older contact.");
        }
 /// <summary>
 /// Make a node on a specific port, with a specified ID
 /// </summary>
 /// <param name="port"></param>
 public KademliaClient(IBucketList cache, IStorage dataStore, Func<Uri, IKadmeliaServer> serverFactory)
 {
     this.routingTable = cache;
     this.dataStore = dataStore;
     this.serverFactory = serverFactory;
     myself = cache.OurContact;
 }
 public KademliaServer(IBucketList cache, IStorage storage, Func<Uri, IKadmeliaServer> serverFactory)
 {
     this.serverFactory = this.serverFactory;
     this.routingTable = cache;
     this._storage = storage;
     this.myself = cache.OurContact;
 }
Beispiel #5
0
        /// <summary>
        /// If cache storage is not explicity provided, we use an in-memory virtual storage.
        /// </summary>
        public Node(Contact contact, IStorage storage, IStorage cacheStorage = null)
        {
            ourContact        = contact;
            bucketList        = new BucketList(contact);
            this.storage      = storage;
            this.cacheStorage = cacheStorage;

            if (cacheStorage == null)
            {
                this.cacheStorage = new VirtualStorage();
            }
        }
        protected IBucketList SetupSplitFailure(IBucketList bucketList = null)
        {
            // force host node ID to < 2^159 so the node ID is not in the 2^159 ... 2^160 range
            byte[] bhostID = new byte[20];
            bhostID[19] = 0x7F;
            ID hostID = new ID(bhostID);

            Contact dummyContact = new Contact(new VirtualProtocol(), hostID);

            ((VirtualProtocol)dummyContact.Protocol).Node = new Node(dummyContact, new VirtualStorage());
            bucketList = bucketList ?? new BucketList(hostID, dummyContact);

            // Also add a contact in this 0 - 2^159 range, arbitrarily something not our host ID.
            // This ensures that only one bucket split will occur after 20 nodes with ID >= 2^159 are added,
            // otherwise, buckets will in the 2^159 ... 2^160 space.
            dummyContact = new Contact(new VirtualProtocol(), ID.One);
            ((VirtualProtocol)dummyContact.Protocol).Node = new Node(dummyContact, new VirtualStorage());
            bucketList.AddContact(new Contact(dummyContact.Protocol, ID.One));

            Assert.IsTrue(bucketList.Buckets.Count == 1, "Bucket split should not have occurred.");
            Assert.IsTrue(bucketList.Buckets[0].Contacts.Count == 1, "Expected 1 contact in bucket 0.");

            // make sure contact ID's all have the same 5 bit prefix and are in the 2^159 ... 2^160 - 1 space
            byte[] bcontactID = new byte[20];
            bcontactID[19] = 0x80;
            // 1000 xxxx prefix, xxxx starts at 1000 (8)
            // this ensures that all the contacts in a bucket match only the prefix as only the first 5 bits are shared.
            // |----| shared range
            // 1000 1000 ...
            // 1000 1100 ...
            // 1000 1110 ...
            byte shifter = 0x08;
            int  pos     = 19;

            Constants.K.ForEach(() =>
            {
                bcontactID[pos] |= shifter;
                ID contactID     = new ID(bcontactID);
                dummyContact     = new Contact(new VirtualProtocol(), ID.One);
                ((VirtualProtocol)dummyContact.Protocol).Node = new Node(dummyContact, new VirtualStorage());
                bucketList.AddContact(new Contact(dummyContact.Protocol, contactID));
                shifter >>= 1;

                if (shifter == 0)
                {
                    shifter = 0x80;
                    --pos;
                }
            });

            return(bucketList);
        }
Beispiel #7
0
        // not perfect, but it's something
        public static long TestBucketList(
            IBucketList <int> list,
            int addOperations,
            int insertOperations,
            int modifyIndexOperations,
            int removeOperations)
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();

            var rnd = new Random();

            while (addOperations > 0 || insertOperations > 0)
            {
                var op = rnd.Next() % 4;
                if ((op == 0 || (addOperations <= 0 && insertOperations <= 0)) &&
                    removeOperations > 0 && list.Size > 0)
                {
                    var index = rnd.Next() % list.Size;
                    list.Remove(index);
                    --removeOperations;
                }
                else if (op == 1 && modifyIndexOperations > 0 && list.Size > 0)
                {
                    var index = rnd.Next() % list.Size;
                    var value = rnd.Next();
                    list[index] = list[index] + value;
                    --modifyIndexOperations;
                }
                else if (op == 2 && insertOperations > 0)
                {
                    var index = rnd.Next() % (list.Size + 1);
                    var value = rnd.Next();
                    list.Insert(index, value);
                    --insertOperations;
                }
                else
                {
                    var value = rnd.Next();
                    list.Add(value);
                    --addOperations;
                }
            }

            stopWatch.Stop();
            return(stopWatch.ElapsedMilliseconds);
        }
        public void NonRespondingContactEvictedTest()
        {
            // Create a DHT so we have an eviction handler.
            Dht dht = new Dht(ID.Zero, new VirtualProtocol(), () => null, new Router());
            //Contact dummyContact = new Contact(new VirtualProtocol(), ID.Zero);
            //((VirtualProtocol)dummyContact.Protocol).Node = new Node(dummyContact, new VirtualStorage());

            IBucketList bucketList = SetupSplitFailure(dht.Node.BucketList);

            Assert.IsTrue(bucketList.Buckets.Count == 2, "Bucket split should have occurred.");
            Assert.IsTrue(bucketList.Buckets[0].Contacts.Count == 1, "Expected 1 contact in bucket 0.");
            Assert.IsTrue(bucketList.Buckets[1].Contacts.Count == 20, "Expected 20 contacts in bucket 1.");

            // The bucket is now full.  Pick the first contact, as it is last seen (they are added in chronological order.)
            Contact nonRespondingContact = bucketList.Buckets[1].Contacts[0];

            // Since the protocols are shared, we need to assign a unique protocol for this node for testing.
            VirtualProtocol vpUnresponding = new VirtualProtocol(((VirtualProtocol)nonRespondingContact.Protocol).Node, false);

            nonRespondingContact.Protocol = vpUnresponding;

            // Setup the next new contact (it can respond.)
            Contact nextNewContact = new Contact(dht.Contact.Protocol, ID.Zero.SetBit(159));

            // Hit the non-responding contact EVICTION_LIMIT times, which will trigger the eviction algorithm.
            Constants.EVICTION_LIMIT.ForEach(() => bucketList.AddContact(nextNewContact));

            Assert.IsTrue(bucketList.Buckets[1].Contacts.Count == 20, "Expected 20 contacts in bucket 1.");

            // Verify CanSplit -> Pending eviction happened.

            Assert.IsTrue(dht.PendingContacts.Count == 0, "Pending contact list should now be empty.");
            Assert.IsFalse(bucketList.Buckets.SelectMany(b => b.Contacts).Contains(nonRespondingContact), "Expected bucket to NOT contain non-responding contact.");
            Assert.IsTrue(bucketList.Buckets.SelectMany(b => b.Contacts).Contains(nextNewContact), "Expected bucket to contain new contact.");
            Assert.IsTrue(dht.EvictionCount.Count == 0, "Expected no contacts to be pending eviction.");
        }
 public BucketListController(IBucketList bucketListService)
 {
     _bucketListService = bucketListService;
 }