public void TooManyContactsTest() { KBucket kbucket = new KBucket(); // Add max # of contacts. Constants.K.ForEach(n => kbucket.AddContact(new Contact(null, new ID(n)))); // Add one more. kbucket.AddContact(new Contact(null, new ID(21))); }
/// <summary> /// Add a contact if possible, based on the algorithm described /// in sections 2.2, 2.4 and 4.2 /// </summary> public void AddContact(Contact contact) { Validate.IsFalse<OurNodeCannotBeAContactException>(ourID == contact.ID, "Cannot add ourselves as a contact!"); contact.Touch(); // Update the LastSeen to now. lock (this) { KBucket kbucket = GetKBucket(contact.ID); if (kbucket.Contains(contact.ID)) { // Replace the existing contact, updating the network info and LastSeen timestamp. kbucket.UpdateContactInfo(contact); } else if (kbucket.IsBucketFull) { if (CanSplit(kbucket)) { // Split the bucket and try again. (KBucket k1, KBucket k2) = kbucket.Split(); int idx = GetKBucketIndex(contact.ID); buckets[idx] = k1; buckets.Insert(idx + 1, k2); buckets[idx].Touch(); buckets[idx + 1].Touch(); AddContact(contact); } else { Contact lastSeenContact = kbucket.Contacts.OrderBy(c => c.LastSeen).First(); RpcError error = lastSeenContact.Protocol.Ping(ourContact); if (error.HasError) { // Null continuation is used because unit tests may not initialize a DHT. dht?.DelayEviction(lastSeenContact, contact); } else { // Still can't add the contact, so put it into the pending list. dht?.AddToPending(contact); } } } else { // Bucket isn't full, so just add the contact. kbucket.AddContact(contact); dht?.ContactAddedToBucket(kbucket, contact); } } }
/// <summary> /// Find a pending contact that goes into the bucket that now has room. /// </summary> protected void ReplaceWithPendingContact(KBucket bucket) { Contact contact; // Non-concurrent list needs locking while we query it. lock (pendingContacts) { contact = pendingContacts.Where(c => node.BucketList.GetKBucket(c.ID) == bucket).OrderBy(c => c.LastSeen).LastOrDefault(); if (contact != null) { pendingContacts.Remove(contact); bucket.AddContact(contact); } } }