public static List<Contact> CloseContacts(this IBucketList _contactCache, ID target, ID excluded) { return _contactCache.CloseContacts(target) .Take(8 * ID.ID_LENGTH) .Where(x => x.GetID() != excluded) .ToList(); }
/// <summary> /// Make a new bucket list, for holding node contacts. /// </summary> /// <param name="ourID">The ID to center the list on.</param> public BucketList(Contact ourID, Func<Uri, IKadmeliaServer> serverFactory) { this.ourID = ourID.GetID(); this.myself = ourID; buckets = new List<List<Contact>>(NUM_BUCKETS); accessTimes = new List<DateTime>(); // Set up each bucket for (int i = 0; i < NUM_BUCKETS; i++) { buckets.Add(new List<Contact>(BUCKET_SIZE)); accessTimes.Add(default(DateTime)); } this.serverFactory = serverFactory; }
/// <summary> /// Returns what bucket an ID maps to. /// PRECONDITION: ourID not passed. /// </summary> /// <param name="id"></param> /// <returns></returns> private int BucketFor(ID id) { return (OurId.DifferingBit(id)); }
public void Touch(ID key) { accessTimes[BucketFor(key)] = DateTime.Now; }
public void Remove(ID toRemove) { int bucket = BucketFor(toRemove); for (int i = 0; i < buckets[bucket].Count; i++) { if (buckets[bucket][i].GetID() == toRemove) { buckets[bucket].RemoveAt(i); return; } } }
public void Promote(ID toPromote) { Contact promotee = Get(toPromote); int bucket = BucketFor(toPromote); buckets[bucket].Remove(promotee); // Take out buckets[bucket].Add(promotee); // And put in at end accessTimes[bucket] = DateTime.Now; }
public Contact Get(ID toGet) { int bucket = BucketFor(toGet); for (int i = 0; i < buckets[bucket].Count; i++) { if (buckets[bucket][i].GetID() == toGet) { return buckets[bucket][i]; } } return null; }
public bool Contains(ID toCheck) { return this.Get(toCheck) != null; }
public IList<Contact> CloseContacts(ID target) { return AllContacts.OrderBy(x => x.GetID() ^ target) .ToList(); }
public Contact Blocker(ID toAdd) { int bucket = BucketFor(toAdd); if (buckets[bucket].Count < BUCKET_SIZE) { return null; } else { return buckets[bucket][0]; } }
/// <summary> /// Determines the least significant bit at which the given ID differs from this one, from 0 through 8 * ID_LENGTH - 1. /// PRECONDITION: IDs do not match. /// </summary> /// <param name="other"></param> /// <returns></returns> public int DifferingBit(ID other) { ID differingBits = this ^ other; int differAt = 0; int i = 0; while (i < ID_LENGTH && differingBits.Data[i] == 0) { differAt += 8; i++; } // Subtract 1 for every zero bit from the right int j = 7; // 1 << j = pow(2, j) while (j >= 0 && (differingBits.Data[i] & (1 << j)) == 0) { j--; differAt++; } return differAt; }
/// <summary> /// Do an iterativeStore operation and publish the key/value pair on the network /// </summary> /// <param name="key"></param> /// <param name="val"></param> private IterativeFindResult IterativeStore(ID key, string val, DateTime originalInsertion, DateTime expires, int replicationFactor) { // Find the K closest nodes to the key var closest = IterativeFindNode(key); foreach (Contact c in closest.ClosestPeers.Take(replicationFactor)) { var remotePeerUri = c.ToUri(); var peer = serverFactory(remotePeerUri); peer.StoreValue(myself, key.Data, val, originalInsertion, expires); } return closest; }
/// <summary> /// Do an iterativeFindNode operation. /// </summary> /// <param name="target"></param> /// <returns></returns> private IterativeFindResult IterativeFindNode(ID target) { return IterativeFind(target, false); }
/// <summary> /// Perform a Kademlia iterativeFind* operation. /// If getValue is true, it sends out a list of strings if values are found, or null none are. /// </summary> /// <param name="target"></param> /// <param name="getValue">true for FindValue, false for FindNode</param> /// <param name="vals"></param> /// <returns></returns> private IterativeFindResult IterativeFind(ID target, bool getValue) { IterativeFindResult result = new IterativeFindResult(); // Log the lookup if (target != routingTable.OurContact.GetID()) routingTable.Touch(target); // Get the alpha closest nodes to the target var shortlist = new SortedList<ID, HaveAsked>(); foreach (Contact c in routingTable.CloseContacts(20, target)) shortlist.Add(c.GetID() ^ target, new HaveAsked() { Contact = c, Asked = false }); // Until we run out of people to ask or we're done... bool peersLeftToAsk = true; while (peersLeftToAsk) { var closestPeerNotAsked = shortlist.Where(x => x.Value.Contact.GetID() != myself.GetID() && !x.Value.IsNotContactable) //Don't ask myself, ignore not contactable nodes .Take(3) //only consider the first 3 closest nodes .Where(x => x.Value.Asked == false) //That we haven't asked before .FirstOrDefault(); //Get the first if (closestPeerNotAsked.Value == null) { peersLeftToAsk = false; continue; } result.NumberIterations += 1; closestPeerNotAsked.Value.Asked = true; var remotePeerUri = closestPeerNotAsked.Value.Contact.ToUri(); var peer = serverFactory(remotePeerUri); SearchResult searchResult; if (getValue) searchResult = peer.FindValue(myself, target.Data); else searchResult = peer.FindNode(myself, target.Data); //peer is down, ignore if (searchResult == null) { closestPeerNotAsked.Value.IsNotContactable = true; continue; } if (searchResult.Values != null) { result.Values = searchResult.Values; result.TargetPeer = closestPeerNotAsked.Value.Contact; return result; } if (searchResult.Contacts != null) { // Add suggestions to shortlist and check for closest foreach (Contact suggestion in searchResult.Contacts) { var distance = suggestion.GetID() ^ target; if (!shortlist.ContainsKey(distance)) shortlist.Add(distance, new HaveAsked() { Contact = suggestion }); //Add this guy to our contact cache routingTable.AddContact(suggestion); } } } result.ClosestPeers = shortlist.Values.Where(x => !x.IsNotContactable).Select(x => x.Contact).Take(20).ToList(); return result; }
public static List<Contact> CloseContacts(this IBucketList _contactCache, int count, ID target) { return _contactCache.CloseContacts(target) .Take(count).ToList(); }