/// <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)); }
/// <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 })); }
/// <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); }