Пример #1
0
        internal static QueryResponseCore CreateSuccess(
            IReadOnlyList <CosmosElement> result,
            double requestCharge,
            string activityId,
            string queryMetricsText,
            IReadOnlyDictionary <string, QueryMetrics> queryMetrics,
            ClientSideRequestStatistics requestStatistics,
            long responseLengthBytes,
            string disallowContinuationTokenMessage,
            string continuationToken)
        {
            QueryResponseCore cosmosQueryResponse = new QueryResponseCore(
                result: result,
                isSuccess: true,
                statusCode: HttpStatusCode.OK,
                requestCharge: requestCharge,
                activityId: activityId,
                queryMetricsText: queryMetricsText,
                queryMetrics: queryMetrics,
                requestStatistics: requestStatistics,
                responseLengthBytes: responseLengthBytes,
                disallowContinuationTokenMessage: disallowContinuationTokenMessage,
                continuationToken: continuationToken,
                errorMessage: null,
                subStatusCode: null);

            return(cosmosQueryResponse);
        }
Пример #2
0
        /// <summary>
        /// Should the caller retry the operation.
        /// </summary>
        /// <param name="exception">Exception that occured when the operation was tried</param>
        /// <param name="cancellationToken"></param>
        /// <returns>True indicates caller should retry, False otherwise</returns>
        public async Task <ShouldRetryResult> ShouldRetryAsync(
            Exception exception,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            this.retryContext = null;
            // Received Connection error (HttpRequestException), initiate the endpoint rediscovery
            HttpRequestException httpException = exception as HttpRequestException;

            if (httpException != null)
            {
                DefaultTrace.TraceWarning("Endpoint not reachable. Refresh cache and retry");
                return(await this.ShouldRetryOnEndpointFailureAsync(this.isReadRequest, false));
            }

            DocumentClientException clientException = exception as DocumentClientException;

            if (clientException?.RequestStatistics != null)
            {
                this.sharedStatistics = clientException.RequestStatistics;
            }

            ShouldRetryResult shouldRetryResult = await this.ShouldRetryInternalAsync(
                clientException?.StatusCode,
                clientException?.GetSubStatus());

            if (shouldRetryResult != null)
            {
                return(shouldRetryResult);
            }

            return(await this.throttlingRetry.ShouldRetryAsync(exception, cancellationToken));
        }
Пример #3
0
 private QueryResponseCore(
     IReadOnlyList <CosmosElement> result,
     bool isSuccess,
     HttpStatusCode statusCode,
     double requestCharge,
     string activityId,
     string queryMetricsText,
     IReadOnlyDictionary <string, QueryMetrics> queryMetrics,
     ClientSideRequestStatistics requestStatistics,
     long responseLengthBytes,
     string disallowContinuationTokenMessage,
     string continuationToken,
     string errorMessage,
     SubStatusCodes?subStatusCode)
 {
     this.IsSuccess           = isSuccess;
     this.CosmosElements      = result;
     this.StatusCode          = statusCode;
     this.ActivityId          = activityId;
     this.QueryMetricsText    = queryMetricsText;
     this.QueryMetrics        = queryMetrics;
     this.ResponseLengthBytes = responseLengthBytes;
     this.RequestCharge       = requestCharge;
     this.DisallowContinuationTokenMessage = disallowContinuationTokenMessage;
     this.ContinuationToken = continuationToken;
     this.ErrorMessage      = errorMessage;
     this.SubStatusCode     = subStatusCode;
     this.RequestStatistics = requestStatistics;
 }
Пример #4
0
        public override async Task <FeedResponse <object> > DrainAsync(int maxElements, CancellationToken token)
        {
            List <object> result      = new List <object>();
            List <Uri>    replicaUris = new List <Uri>();
            ClientSideRequestStatistics requestStats = new ClientSideRequestStatistics();

            while (!this.IsDone)
            {
                DocumentProducer <object> currentDocumentProducer = base.DocumentProducers[this.currentDocumentProducerIndex];

                if (currentDocumentProducer.IsAtContinuationBoundary)
                {
                    if (maxElements - result.Count < currentDocumentProducer.ItemsTillNextContinuationBoundary)
                    {
                        break;
                    }

                    base.CurrentContinuationTokens[currentDocumentProducer] = currentDocumentProducer.ResponseContinuation;

                    result.Add(currentDocumentProducer.Current);

                    if (currentDocumentProducer.RequestStatistics != null)
                    {
                        replicaUris.AddRange(currentDocumentProducer.RequestStatistics.ContactedReplicas);
                    }

                    while (currentDocumentProducer.ItemsTillNextContinuationBoundary > 1)
                    {
                        bool hasMoreResults = await currentDocumentProducer.MoveNextAsync(token);

                        Debug.Assert(hasMoreResults, "Expect hasMoreResults be true.");
                        result.Add(currentDocumentProducer.Current);
                    }
                }

                if (!await this.TryMoveNextProducerAsync(currentDocumentProducer, token))
                {
                    ++this.currentDocumentProducerIndex;

                    if (this.currentDocumentProducerIndex < base.DocumentProducers.Count &&
                        !base.CurrentContinuationTokens.ContainsKey(base.DocumentProducers[this.currentDocumentProducerIndex]))
                    {
                        base.CurrentContinuationTokens[base.DocumentProducers[this.currentDocumentProducerIndex]] = null;
                    }

                    continue;
                }

                if (maxElements >= int.MaxValue && result.Count > this.ActualMaxBufferedItemCount)
                {
                    break;
                }
            }

            this.ReduceTotalBufferedItems(result.Count);
            requestStats.ContactedReplicas.AddRange(replicaUris);

            return(new FeedResponse <object>(result, result.Count, this.ResponseHeaders, requestStats, this.GetAndResetResponseLengthBytes()));
        }
Пример #5
0
        public override async Task <FeedResponse <object> > DrainAsync(int maxElements, CancellationToken token)
        {
            List <object> result      = new List <object>();
            List <Uri>    replicaUris = new List <Uri>();
            ClientSideRequestStatistics requestStats = new ClientSideRequestStatistics();

            if (maxElements >= int.MaxValue)
            {
                maxElements = this.ActualMaxBufferedItemCount;
            }

            while (!this.IsDone && result.Count < maxElements)
            {
                this.UpdateCurrentDocumentProducer();

                DefaultTrace.TraceVerbose(string.Format(
                                              CultureInfo.InvariantCulture,
                                              "{0}, CorrelatedActivityId: {1}, ActivityId: {2} | OrderBy~Context.DrainAsync, currentDocumentProducer.Id: {3}, documentProducerConsumeQueue.Count: {4}",
                                              DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture),
                                              this.CorrelatedActivityId,
                                              this.ActivityId,
                                              this.currentDocumentProducer.TargetRange.Id,
                                              this.documentProducerConsumerQueue.Count));

                OrderByQueryResult orderByResult = (OrderByQueryResult)this.currentDocumentProducer.Current;

                result.Add(orderByResult.Payload);

                if (this.currentDocumentProducer.RequestStatistics != null)
                {
                    replicaUris.AddRange(this.currentDocumentProducer.RequestStatistics.ContactedReplicas);
                }

                if (this.ShouldIncrementSkipCount(orderByResult.Rid))
                {
                    ++this.skipCount;
                }
                else
                {
                    this.skipCount = 0;
                }

                this.previousRid = orderByResult.Rid;

                if (!await this.TryMoveNextProducerAsync(
                        this.currentDocumentProducer,
                        null,
                        cancellationToken: token))
                {
                    this.currentDocumentProducer = null;
                }
            }

            this.ReduceTotalBufferedItems(result.Count);
            requestStats.ContactedReplicas.AddRange(replicaUris);

            return(new FeedResponse <object>(result, result.Count, this.ResponseHeaders, requestStats, this.GetAndResetResponseLengthBytes()));
        }
Пример #6
0
 internal FeedResponse(
     IEnumerable <T> result,
     int count,
     INameValueCollection responseHeaders,
     ClientSideRequestStatistics requestStats,
     long responseLengthBytes)
     : this(result, count, responseHeaders, false, null, requestStats, responseLengthBytes : responseLengthBytes)
 {
 }
Пример #7
0
        public override async Task <FeedResponse <object> > DrainAsync(int maxElements, CancellationToken token)
        {
            // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document.
            double     requestCharge       = 0;
            long       responseLengthBytes = 0;
            List <Uri> replicaUris         = new List <Uri>();
            ClientSideRequestStatistics requestStatistics = new ClientSideRequestStatistics();

            while (!this.IsDone)
            {
                FeedResponse <object> result = await base.DrainAsync(int.MaxValue, token);

                requestCharge       += result.RequestCharge;
                responseLengthBytes += result.ResponseLengthBytes;

                if (result.RequestStatistics != null)
                {
                    replicaUris.AddRange(result.RequestStatistics.ContactedReplicas);
                }

                foreach (dynamic item in result)
                {
                    AggregateItem[] values = (AggregateItem[])item;
                    Debug.Assert(values.Length == this.aggregators.Length, string.Format(
                                     CultureInfo.InvariantCulture,
                                     "Expect {0} values, but received {1}.",
                                     this.aggregators.Length,
                                     values.Length));

                    for (int i = 0; i < this.aggregators.Length; ++i)
                    {
                        this.aggregators[i].Aggregate(values[i].GetItem());
                    }
                }
            }

            List <object> finalResult = this.BindAggregateResults(
                this.aggregators.Select(aggregator => aggregator.GetResult()).ToArray());

            // The replicaUris may have duplicates.
            requestStatistics.ContactedReplicas.AddRange(replicaUris);

            return(new FeedResponse <object>(
                       finalResult,
                       finalResult.Count,
                       new StringKeyValueCollection()
            {
                { HttpConstants.HttpHeaders.RequestCharge, requestCharge.ToString(CultureInfo.InvariantCulture) }
            },
                       requestStatistics,
                       responseLengthBytes));
        }
Пример #8
0
        public ClientRetryPolicy(
            GlobalEndpointManager globalEndpointManager,
            bool enableEndpointDiscovery,
            RetryOptions retryOptions)
        {
            this.throttlingRetry = new ResourceThrottleRetryPolicy(
                retryOptions.MaxRetryAttemptsOnThrottledRequests,
                retryOptions.MaxRetryWaitTimeInSeconds);

            this.globalEndpointManager        = globalEndpointManager;
            this.failoverRetryCount           = 0;
            this.enableEndpointDiscovery      = enableEndpointDiscovery;
            this.sessionTokenRetryCount       = 0;
            this.canUseMultipleWriteLocations = false;

            this.sharedStatistics = new ClientSideRequestStatistics();
        }
Пример #9
0
 internal FeedResponse(
     IEnumerable <T> result,
     int count,
     INameValueCollection responseHeaders,
     bool useETagAsContinuation = false,
     IReadOnlyDictionary <string, QueryMetrics> queryMetrics = null,
     ClientSideRequestStatistics requestStats = null,
     string disallowContinuationTokenMessage  = null,
     long responseLengthBytes = 0)
     : this(result)
 {
     this.Count                            = count;
     this.responseHeaders                  = (INameValueCollection)responseHeaders.Clone();
     this.usageHeaders                     = new Dictionary <string, long>();
     this.quotaHeaders                     = new Dictionary <string, long>();
     this.useETagAsContinuation            = useETagAsContinuation;
     this.queryMetrics                     = queryMetrics;
     this.RequestStatistics                = requestStats;
     this.disallowContinuationTokenMessage = disallowContinuationTokenMessage;
     this.ResponseLengthBytes              = responseLengthBytes;
 }
Пример #10
0
        /// <summary>
        /// Drains at most 'maxElements' documents from the AggregateDocumentQueryExecutionComponent.
        /// </summary>
        /// <param name="maxElements">This value is ignored, since the aggregates are aggregated for you.</param>
        /// <param name="token">The cancellation token.</param>
        /// <returns>The aggregate result after all the continuations have been followed.</returns>
        /// <remarks>
        /// Note that this functions follows all continuations meaning that it won't return until all continuations are drained.
        /// This means that if you have a long running query this function will take a very long time to return.
        /// </remarks>
        public override async Task <FeedResponse <CosmosElement> > DrainAsync(int maxElements, CancellationToken token)
        {
            // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document.
            double     requestCharge       = 0;
            long       responseLengthBytes = 0;
            List <Uri> replicaUris         = new List <Uri>();
            ClientSideRequestStatistics requestStatistics       = new ClientSideRequestStatistics();
            PartitionedQueryMetrics     partitionedQueryMetrics = new PartitionedQueryMetrics();

            while (!this.IsDone)
            {
                FeedResponse <CosmosElement> result = await base.DrainAsync(int.MaxValue, token);

                requestCharge           += result.RequestCharge;
                responseLengthBytes     += result.ResponseLengthBytes;
                partitionedQueryMetrics += new PartitionedQueryMetrics(result.QueryMetrics);
                if (result.RequestStatistics != null)
                {
                    replicaUris.AddRange(result.RequestStatistics.ContactedReplicas);
                }

                foreach (CosmosElement item in result)
                {
                    if (!(item is CosmosArray comosArray))
                    {
                        throw new InvalidOperationException("Expected an array of aggregate results from the execution context.");
                    }

                    List <AggregateItem> aggregateItems = new List <AggregateItem>();
                    foreach (CosmosElement arrayItem in comosArray)
                    {
                        aggregateItems.Add(new AggregateItem(arrayItem));
                    }

                    Debug.Assert(
                        aggregateItems.Count == this.aggregators.Length,
                        $"Expected {this.aggregators.Length} values, but received {aggregateItems.Count}.");

                    for (int i = 0; i < this.aggregators.Length; ++i)
                    {
                        this.aggregators[i].Aggregate(aggregateItems[i].Item);
                    }
                }
            }

            List <CosmosElement> finalResult = this.BindAggregateResults(
                this.aggregators.Select(aggregator => aggregator.GetResult()));

            // The replicaUris may have duplicates.
            requestStatistics.ContactedReplicas.AddRange(replicaUris);

            return(new FeedResponse <CosmosElement>(
                       finalResult,
                       finalResult.Count,
                       new StringKeyValueCollection()
            {
                {
                    HttpConstants.HttpHeaders.RequestCharge,
                    requestCharge.ToString(CultureInfo.InvariantCulture)
                }
            },
                       useETagAsContinuation: false,
                       queryMetrics: partitionedQueryMetrics,
                       requestStats: requestStatistics,
                       disallowContinuationTokenMessage: null,
                       responseLengthBytes: responseLengthBytes));
        }
Пример #11
0
        /// <summary>
        /// Drains at most 'maxElements' documents from the AggregateDocumentQueryExecutionComponent.
        /// </summary>
        /// <param name="maxElements">This value is ignored, since the aggregates are aggregated for you.</param>
        /// <param name="token">The cancellation token.</param>
        /// <returns>The aggregate result after all the continuations have been followed.</returns>
        /// <remarks>
        /// Note that this functions follows all continuations meaning that it won't return until all continuations are drained.
        /// This means that if you have a long running query this function will take a very long time to return.
        /// </remarks>
        public override async Task <QueryResponse> DrainAsync(int maxElements, CancellationToken token)
        {
            // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document.
            // Note-2019-07-11-brchon: We can return empty pages until all the documents are drained,
            // but then we will have to design a continuation token.

            double     requestCharge       = 0;
            long       responseLengthBytes = 0;
            List <Uri> replicaUris         = new List <Uri>();
            ClientSideRequestStatistics requestStatistics       = new ClientSideRequestStatistics();
            PartitionedQueryMetrics     partitionedQueryMetrics = new PartitionedQueryMetrics();
            ResourceType resourceType = ResourceType.Document;
            string       containerRid = null;

            while (!this.IsDone)
            {
                QueryResponse result = await base.DrainAsync(int.MaxValue, token);

                if (!result.IsSuccessStatusCode)
                {
                    return(result);
                }

                containerRid         = result.QueryHeaders.ContainerRid;
                resourceType         = result.QueryHeaders.ResourceType;
                requestCharge       += result.Headers.RequestCharge;
                responseLengthBytes += result.ResponseLengthBytes;
                // DEVNOTE: Add when query metrics is supported
                // partitionedQueryMetrics += new PartitionedQueryMetrics(results.QueryMetrics);
                if (result.RequestStatistics != null)
                {
                    replicaUris.AddRange(result.RequestStatistics.ContactedReplicas);
                }

                foreach (CosmosElement element in result.CosmosElements)
                {
                    RewrittenAggregateProjections rewrittenAggregateProjections = new RewrittenAggregateProjections(
                        this.isValueAggregateQuery,
                        element);
                    this.singleGroupAggregator.AddValues(rewrittenAggregateProjections.Payload);
                }
            }

            List <CosmosElement> finalResult       = new List <CosmosElement>();
            CosmosElement        aggregationResult = this.singleGroupAggregator.GetResult();

            if (aggregationResult != null)
            {
                finalResult.Add(aggregationResult);
            }

            // The replicaUris may have duplicates.
            requestStatistics.ContactedReplicas.AddRange(replicaUris);

            return(QueryResponse.CreateSuccess(
                       result: finalResult,
                       count: finalResult.Count,
                       responseLengthBytes: responseLengthBytes,
                       responseHeaders: new CosmosQueryResponseMessageHeaders(
                           continauationToken: null,
                           disallowContinuationTokenMessage: null,
                           resourceType: resourceType,
                           containerRid: containerRid)
            {
                RequestCharge = requestCharge
            },
                       queryMetrics: this.GetQueryMetrics()));
        }
Пример #12
0
        /// <summary>
        /// Drains at most 'maxElements' documents from the <see cref="AggregateDocumentQueryExecutionComponent"/> .
        /// </summary>
        /// <param name="maxElements">This value is ignored, since the aggregates are aggregated for you.</param>
        /// <param name="token">The cancellation token.</param>
        /// <returns>The aggregate result after all the continuations have been followed.</returns>
        /// <remarks>
        /// Note that this functions follows all continuations meaning that it won't return until all continuations are drained.
        /// This means that if you have a long running query this function will take a very long time to return.
        /// </remarks>
        public override async Task <QueryResponse> DrainAsync(int maxElements, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document.
            double     requestCharge       = 0;
            long       responseLengthBytes = 0;
            List <Uri> replicaUris         = new List <Uri>();
            ClientSideRequestStatistics requestStatistics       = new ClientSideRequestStatistics();
            PartitionedQueryMetrics     partitionedQueryMetrics = new PartitionedQueryMetrics();

            while (!this.IsDone)
            {
                QueryResponse result = await base.DrainAsync(int.MaxValue, token);

                if (!result.IsSuccessStatusCode)
                {
                    return(result);
                }

                requestCharge       += result.Headers.RequestCharge;
                responseLengthBytes += result.ResponseLengthBytes;
                //partitionedQueryMetrics += new PartitionedQueryMetrics(result.QueryMetrics);
                if (result.RequestStatistics != null)
                {
                    replicaUris.AddRange(result.RequestStatistics.ContactedReplicas);
                }

                foreach (CosmosElement item in result.CosmosElements)
                {
                    if (!(item is CosmosArray comosArray))
                    {
                        throw new InvalidOperationException("Expected an array of aggregate results from the execution context.");
                    }

                    List <AggregateItem> aggregateItems = new List <AggregateItem>();
                    foreach (CosmosElement arrayItem in comosArray)
                    {
                        aggregateItems.Add(new AggregateItem(arrayItem));
                    }

                    Debug.Assert(
                        aggregateItems.Count == this.aggregators.Length,
                        $"Expected {this.aggregators.Length} values, but received {aggregateItems.Count}.");

                    for (int i = 0; i < this.aggregators.Length; ++i)
                    {
                        this.aggregators[i].Aggregate(aggregateItems[i].Item);
                    }
                }
            }

            List <CosmosElement> finalResult = this.BindAggregateResults(
                this.aggregators.Select(aggregator => aggregator.GetResult()));

            // The replicaUris may have duplicates.
            requestStatistics.ContactedReplicas.AddRange(replicaUris);

            return(QueryResponse.CreateSuccess(
                       result: finalResult,
                       count: finalResult.Count,
                       responseLengthBytes: responseLengthBytes,
                       responseHeaders: new CosmosQueryResponseMessageHeaders(continauationToken: null, disallowContinuationTokenMessage: null)
            {
                RequestCharge = requestCharge
            }));
        }