예제 #1
0
 /// <summary>
 /// Sends a request and waits for the response
 /// </summary>
 /// <returns>The connection request async.</returns>
 /// <param name="channel">The channel to send the request over</param>
 /// <param name="endPoint">End point.</param>
 /// <param name="key">Key.</param>
 /// <param name="request">Request.</param>
 public static Task <ConnectionResponse> SendConnectionRequestAsync(this IWriteChannel <ConnectionRequest> channel, EndPoint endPoint, Key key, Protocol.Request request)
 {
     return(SendConnectionRequestAsync(channel, endPoint, key, 0, request));
 }
예제 #2
0
 /// <summary>
 /// Sends a request and waits for the response
 /// </summary>
 /// <returns>The connection request async.</returns>
 /// <param name="channel">The channel to send the request over</param>
 /// <param name="endPoint">End point.</param>
 /// <param name="key">Key.</param>
 /// <param name="requestId">The request ID</param>
 /// <param name="request">Request.</param>
 public static Task <ConnectionResponse> SendConnectionRequestAsync(this IWriteChannel <ConnectionRequest> channel, EndPoint endPoint, Key key, long requestId, Protocol.Request request)
 {
     return(SendMessageAsync <ConnectionRequest, ConnectionResponse>(channel, new ConnectionRequest()
     {
         EndPoint = endPoint,
         Key = key,
         RequestID = requestId,
         Request = request
     }));
 }
예제 #3
0
        /// <summary>
        /// Visits the <paramref name="k"/> closest peers and sends the <paramref name="request"/> message to them
        /// </summary>
        /// <returns>The number of nodes visited.</returns>
        /// <param name="selfinfo">Selfinfo.</param>
        /// <param name="key">The key to use for findng the closest nodes.</param>
        /// <param name="k">The redundancy parameter.</param>
        /// <param name="succes_count">The number of success responses to find</param>
        /// <param name="request">The request to send.</param>
        private static async Task <List <Protocol.Response> > VisitClosestPeers(PeerInfo selfinfo, Key key, int k, int succes_count, Protocol.Request request)
        {
            KeyDistance closesttried = null;

            var peers = await GetClosestPeers(selfinfo, key, k);

            log.Debug($"Initial query gave {peers.Count} peers");

            var used = new HashSet <Key>();

            var lck     = new object();
            var closest = new List <PeerInfo>();

            var cb = Channels.ConnectionBrokerRequests.Get();

            var success = new List <Protocol.Response>();

            using (var tp = new TaskPool <PeerInfo>(2, (p, ex) => log.Warn($"Request to peer {p.Key} - {p.Address} failed", ex)))
                while (success.Count < succes_count && (peers.Count + closest.Count > 0))
                {
                    peers = closest
                            .Union(peers)
                            // Remove dead items
                            .Where(x => !used.Contains(x.Key))
                            // Always move closer to the target for find
                            .Where(x => closesttried == null || (new KeyDistance(key, x.Key).CompareTo(closesttried)) <= 0)
                            // Sort by distance
                            .OrderBy(x => new KeyDistance(key, x.Key))
                            .ToList();

                    // Clean the list
                    closest.Clear();

                    log.Debug($"Sending request to {peers.Count} peers");

                    // Get the peers
                    var alloperations =
                        peers.Select(x => tp.Run(x, async() =>
                    {
                        log.Debug($"Success count {success.Count}, target: {succes_count}");
                        if (success.Count >= succes_count)
                        {
                            return;
                        }

                        log.Debug("Sending request via broker");
                        var r = cb.SendConnectionRequestAsync(x.Address, x.Key, request);

                        // Don't try this again
                        lock (lck)
                            used.Add(x.Key);

                        log.Debug($"Waiting for broker response {x.Key}...");
                        var res = await r;
                        log.Debug($"Peer response for {x.Key} obtained ({(res.Exception != null ? "exception": (res.Response.Success ? "success" : "no hit"))})");

                        // Skip error nodes
                        if (res.Exception != null)
                        {
                            log.Warn("Node request failed", res.Exception);
                            //await Channels.ConnectionBrokerRegistrations.Get().WriteAsync(new ConnectionRegistrationRequest() {
                            //    IsTerminate = true,
                            //    UpdateRouting = true,
                            //    Peer = x
                            //});

                            return;
                        }
                        // Record success
                        if (res.Response.Success)
                        {
                            lock (lck)
                                success.Add(res.Response);
                        }

                        // Stock up on peers, if any
                        if (res.Response.Peers != null)
                        {
                            lock (lck)
                                closest.AddRange(res.Response.Peers);
                        }

                        // If we are doing a find, narrow the scope
                        if (request.Operation == Protocol.Operation.FindValue)
                        {
                            if (closesttried == null || new KeyDistance(key, x.Key).CompareTo(closesttried) < 0)
                            {
                                closesttried = new KeyDistance(key, x.Key);
                            }
                        }
                    }));

                    await Task.WhenAll(alloperations);

                    await tp.FinishedAsync();

                    log.Debug($"Got {closest.Count} potential new peers");

                    if (closest.Count == 0)
                    {
                        break;
                    }
                }

            return(success);
        }