/// <summary> /// Executes the <see cref="IQueryRequest"/> against the Couchbase server asynchronously. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="queryRequest">The query request.</param> /// <param name="cancellationToken">Token which can cancel the query.</param> /// <returns></returns> public async Task <IQueryResult <T> > QueryAsync <T>(IQueryRequest queryRequest, CancellationToken cancellationToken) { //shortcut for adhoc requests if (queryRequest.IsAdHoc) { return(await ExecuteQueryAsync <T>(queryRequest, cancellationToken).ContinueOnAnyContext()); } //optimize, return an error result if optimization step cannot complete try { await PrepareStatementIfNotAdHocAsync(queryRequest, cancellationToken).ContinueOnAnyContext(); } catch (Exception e) { var errorResult = new QueryResult <T>(); ProcessError(e, errorResult); return(errorResult); } // execute optimized query var result = await ExecuteQueryAsync <T>(queryRequest, cancellationToken).ContinueOnAnyContext(); // if the query failed, check if the query plan should be evicted if (!result.Success && result.IsQueryPlanStale()) { var originalStatement = queryRequest.GetOriginalStatement(); _queryCache.TryRemove(originalStatement, out QueryPlan _); } return(result); }
/// <summary> /// Prepares the statement if the <see cref="IQueryRequest"/> is not ad-hoc and caches it for reuse.asynchronously. /// </summary> /// <param name="originalRequest">The original query request.</param> /// <param name="cancellationToken">Token which can cancel the query.</param> private async Task PrepareStatementIfNotAdHocAsync(IQueryRequest originalRequest, CancellationToken cancellationToken) { if (originalRequest.IsAdHoc) { return; } var originalStatement = originalRequest.GetOriginalStatement(); if (_queryCache.TryGetValue(originalStatement, out var queryPlan)) { originalRequest.Prepared(queryPlan, originalStatement); } else { var result = await PrepareAsync(originalRequest, cancellationToken).ContinueOnAnyContext(); if (!result.Success) { throw new PrepareStatementException("Unable to optimize async statement: " + result.GetErrorsAsString()); } queryPlan = result.FirstOrDefault(); if (queryPlan != null && _queryCache.TryAdd(originalStatement, queryPlan)) { originalRequest.Prepared(queryPlan, originalStatement); } } }
/// <summary> /// Prepares the statement if the <see cref="IQueryRequest"/> is not ad-hoc and caches it for reuse.asynchronously. /// </summary> /// <param name="originalRequest">The original query request.</param> async Task PrepareStatementIfNotAdHocAsync(IQueryRequest originalRequest) { if (originalRequest.IsAdHoc) { return; } var originalStatement = originalRequest.GetOriginalStatement(); QueryPlan queryPlan; if (_queryCache.TryGetValue(originalStatement, out queryPlan)) { originalRequest.Prepared(queryPlan, originalStatement); } else { var result = await PrepareAsync(originalRequest); if (!result.Success) { Log.WarnFormat("Failure to prepare async plan for query {0} (it will be reattempted next time it is issued): {1}", originalStatement, result.GetErrorsAsString()); throw new PrepareStatementException("Unable to optimize async statement: " + result.GetErrorsAsString()); } queryPlan = result.Rows.FirstOrDefault(); if (queryPlan != null && _queryCache.TryAdd(originalStatement, queryPlan)) { originalRequest.Prepared(queryPlan, originalStatement); } } }
internal static ISpanBuilder BuildSpan(this ITracer tracer, IQueryRequest query, string operationName) { return(tracer.BuildSpan(operationName) .WithTag(CouchbaseTags.OperationId, query.CurrentContextId) .WithTag(CouchbaseTags.Service, CouchbaseTags.ServiceN1ql) .WithTag(Tags.DbStatement, query.GetOriginalStatement()) .AsChildOf(query.ActiveSpan)); }
/// <summary> /// Prepare an ad-hoc N1QL statement for later execution against a Couchbase Server. /// </summary> /// <param name="toPrepare">The <see cref="IQueryRequest" /> containing a N1QL statement to be prepared.</param> /// <returns> /// A <see cref="IQueryResult{T}" /> containing the <see cref="QueryPlan" /> representing the reusable /// and cachable execution plan for the statement. /// </returns> /// <remarks> /// Most parameters in the IQueryRequest will be ignored, appart from the Statement and the BaseUri. /// </remarks> public IQueryResult<QueryPlan> Prepare(IQueryRequest toPrepare) { var statement = toPrepare.GetOriginalStatement(); if (!statement.ToUpper().StartsWith("PREPARE ")) { statement = string.Concat("PREPARE ", statement); } var query = new QueryRequest(statement); query.BaseUri(toPrepare.GetBaseUri()); return ExecuteQuery<QueryPlan>(query); }
/// <summary> /// Prepare an ad-hoc N1QL statement for later execution against a Couchbase Server asynchronously /// </summary> /// <param name="toPrepare">The <see cref="IQueryRequest" /> containing a N1QL statement to be prepared.</param> /// <param name="cancellationToken">Token which can cancel the query.</param> /// <returns> /// A <see cref="IQueryResult{T}" /> containing the <see cref="QueryPlan" /> representing the reusable /// and cachable execution plan for the statement. /// </returns> /// <remarks> /// Most parameters in the IQueryRequest will be ignored, appart from the Statement and the BaseUri. /// </remarks> public async Task<IQueryResult<QueryPlan>> PrepareAsync(IQueryRequest toPrepare, CancellationToken cancellationToken) { var statement = toPrepare.GetOriginalStatement(); if (!statement.ToUpper().StartsWith("PREPARE ")) { statement = string.Concat("PREPARE ", statement); } var query = new QueryRequest(statement); query.BaseUri(toPrepare.GetBaseUri()); return await ExecuteQueryAsync<QueryPlan>(query, cancellationToken).ContinueOnAnyContext(); }
public QueryTimer(IQueryRequest queryRequest, ITimingStore store, bool enableQueryTiming) { Store = store; if (!store.Enabled || !enableQueryTiming) return; if (queryRequest == null) { throw new ArgumentException(QueryMustBeProvided); } if (string.IsNullOrEmpty(queryRequest.GetOriginalStatement())) { throw new ArgumentException(QueryStatementMustBeProvided); } _statement = queryRequest.GetOriginalStatement(); _enableQueryTiming = enableQueryTiming; ClusterElapsedTime = NotRecorded; _stopwatch = Stopwatch.StartNew(); }
private async Task <IQueryResult <T> > RetryAsync <T>(IQueryRequest queryRequest, CancellationToken cancellationToken) { //mark as retried, remove from cache queryRequest.HasBeenRetried = true; _queryCache.TryRemove(queryRequest.GetOriginalStatement(), out QueryPlan _); //re-optimize asynchronously await PrepareStatementIfNotAdHocAsync(queryRequest, cancellationToken).ContinueOnAnyContext(); //re-execute asynchronously return(await ExecuteQueryAsync <T>(queryRequest, cancellationToken).ContinueOnAnyContext()); }
public QueryTimer(IQueryRequest queryRequest, ITimingStore store, bool enableQueryTiming) { if (!store.Enabled || !enableQueryTiming) { return; } if (queryRequest == null) { throw new ArgumentException(QueryMustBeProvided); } if (string.IsNullOrEmpty(queryRequest.GetOriginalStatement())) { throw new ArgumentException(QueryStatementMustBeProvided); } Store = store; _contextId = queryRequest.CurrentContextId; _statement = queryRequest.GetOriginalStatement(); ClusterElapsedTime = NotRecorded; _stopwatch = Stopwatch.StartNew(); }
private async Task <IQueryResult <T> > RetryAsync <T>(IQueryRequest queryRequest) { //mark as retried, remove from cache queryRequest.HasBeenRetried = true; QueryPlan dismissed; _queryCache.TryRemove(queryRequest.GetOriginalStatement(), out dismissed); //re-optimize asynchronously await PrepareStatementIfNotAdHocAsync(queryRequest); //re-execute asynchronously return(await ExecuteQueryAsync <T>(queryRequest)); }
private IQueryResult<T> Retry<T>(IQueryRequest queryRequest) { //mark as retried, remove from cache string key = queryRequest.GetOriginalStatement(); queryRequest.HasBeenRetried = true; QueryPlan dismissed; _queryCache.TryRemove(key, out dismissed); //re-optimize PrepareStatementIfNotAdHoc(queryRequest); //re-execute return ExecuteQuery<T>(queryRequest); }