Esempio n. 1
0
        /// <summary>
        /// Finds the closest contact in the network. Does several round trips to the network
        /// </summary>
        /// <param name="target">The target.</param>
        /// <returns>an IEnumerable&lt;contact&gt; in order of distance from the target. Can be cast into a GetClosestNodes.ClosestResults</contact></returns>
        public IEnumerable <Contact> GetClosestContacts(Identifier512 target, Func <Contact, bool> terminate = null)
        {
            MinMaxHeap <Contact> heap = new MinMaxHeap <Contact>(new ContactComparer(target), contacts.ClosestNodes(target).Take(RoutingTable.Configuration.LookupConcurrency));

            HashSet <Identifier512> contacted = new HashSet <Identifier512>();

            contacted.Add(RoutingTable.LocalIdentifier);

            int iterations = 0;
            HashSet <Contact> uniqueDiscoveries;

            do
            {
                iterations++;

                uniqueDiscoveries = new HashSet <Contact>(                                                      //hashet means we only get each result once
                    heap                                                                                        //from the set of results we know about
                    .Where(c => !contacted.Contains(c.Identifier))                                              //which we have not already contacted
                    .SelectMany(c =>
                {
                    try { return(RemoteGetClosest(RoutingTable.LocalContact, c, target, RoutingTable.Configuration.LookupConcurrency, RoutingTable.Configuration.LookupTimeout)); }
                    catch (TimeoutException) { return(null); }
                })                                                                                          //select the closest ones they know about
                    .Where(n => n != null)
                    .Where(r => !heap.Contains(r)));                                                        //remove the results we already know about

                //Make the system aware of these potentially new nodes
                foreach (var c in uniqueDiscoveries)
                {
                    contacts.Update(c);
                }

                //make sure we never contact these nodes again
                contacted.UnionWith(heap.Select(a => a.Identifier));

                //add the new results
                heap.AddMany(uniqueDiscoveries);

                while (heap.Count > RoutingTable.Configuration.LookupConcurrency)
                {
                    heap.RemoveMax();
                }

                if (terminate != null)
                {
                    if (uniqueDiscoveries.Where(a => terminate(a)).FirstOrDefault() != null)
                    {
                        break;
                    }
                }
            }while (uniqueDiscoveries.Count != 0 && heap.Minimum.Identifier != target);

            return(new ClosestResults(heap, iterations));
            //while (heap.Count > 0)
            //    yield return heap.RemoveMin();
        }