private async Task <PrepareResult> SendRequestToOneNode(IInternalSession session, IEnumerator <Host> queryPlan, InternalPrepareRequest request) { var triedHosts = new Dictionary <IPEndPoint, Exception>(); while (true) { // It may throw a NoHostAvailableException which we should yield to the caller var hostConnectionTuple = await GetNextConnection(session, queryPlan, triedHosts).ConfigureAwait(false); var connection = hostConnectionTuple.Item2; var host = hostConnectionTuple.Item1; try { var result = await connection.Send(request).ConfigureAwait(false); return(new PrepareResult { PreparedStatement = await GetPreparedStatement(result, request, request.Keyspace ?? connection.Keyspace, session.Cluster).ConfigureAwait(false), TriedHosts = triedHosts, HostAddress = host.Address }); } catch (Exception ex) when(PrepareHandler.CanBeRetried(ex)) { triedHosts[host.Address] = ex; } } }
/// <summary> /// Executes the prepare request on the first host selected by the load balancing policy. /// When <see cref="QueryOptions.IsPrepareOnAllHosts"/> is enabled, it prepares on the rest of the hosts in /// parallel. /// </summary> internal static async Task <PreparedStatement> Prepare(IInternalSession session, Serializer serializer, PrepareRequest request) { var cluster = session.InternalCluster; var lbp = cluster.Configuration.Policies.LoadBalancingPolicy; var handler = new PrepareHandler(serializer, lbp.NewQueryPlan(session.Keyspace, null).GetEnumerator()); var ps = await handler.Prepare(request, session, null).ConfigureAwait(false); var psAdded = cluster.PreparedQueries.GetOrAdd(ps.Id, ps); if (ps != psAdded) { Logger.Warning("Re-preparing already prepared query is generally an anti-pattern and will likely " + "affect performance. Consider preparing the statement only once. Query='{0}'", ps.Cql); ps = psAdded; } var prepareOnAllHosts = cluster.Configuration.QueryOptions.IsPrepareOnAllHosts(); if (!prepareOnAllHosts) { return(ps); } await handler.PrepareOnTheRestOfTheNodes(request, session).ConfigureAwait(false); return(ps); }