protected async Task InitializeAsync( string collectionRid, List <Range <string> > queryRanges, Func <DocumentProducer <T>, int> taskPriorityFunc, IReadOnlyList <PartitionKeyRange> partitionKeyRanges, int initialPageSize, SqlQuerySpec querySpecForInit, Dictionary <string, string> targetRangeToContinuationMap, CancellationToken token) { CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); INameValueCollection requestHeaders = await this.CreateCommonHeadersAsync(this.GetFeedOptions(null)); DefaultTrace.TraceInformation(string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {1} | Parallel~ContextBase.InitializeAsync, MaxBufferedItemCount: {2}, Target PartitionKeyRange Count: {3}, MaximumConcurrencyLevel: {4}, DocumentProducer Initial Page Size {5}", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), this.CorrelatedActivityId, this.actualMaxBufferedItemCount, partitionKeyRanges.Count, this.TaskScheduler.MaximumConcurrencyLevel, initialPageSize)); foreach (PartitionKeyRange range in partitionKeyRanges) { string initialContinuationToken = (targetRangeToContinuationMap != null && targetRangeToContinuationMap.ContainsKey(range.Id)) ? targetRangeToContinuationMap[range.Id] : null; this.DocumentProducers.Add(new DocumentProducer <T>( this.TaskScheduler, (continuationToken, pageSize) => { INameValueCollection headers = requestHeaders.Clone(); headers[HttpConstants.HttpHeaders.Continuation] = continuationToken; headers[HttpConstants.HttpHeaders.PageSize] = pageSize.ToString(CultureInfo.InvariantCulture); return(this.CreateDocumentServiceRequest( headers, querySpecForInit, range, collectionRid)); }, range, taskPriorityFunc, this.ExecuteRequestAsync <T>, () => new NonRetriableInvalidPartitionExceptionRetryPolicy(collectionCache, this.Client.RetryPolicy.GetRequestPolicy()), this.OnDocumentProducerCompleteFetching, this.CorrelatedActivityId, initialPageSize, initialContinuationToken)); if (!string.IsNullOrEmpty(initialContinuationToken)) { this.CurrentContinuationTokens[this.DocumentProducers[this.DocumentProducers.Count - 1]] = initialContinuationToken; } } }
internal DocumentFeedResponse( IEnumerable <T> result, int count, INameValueCollection responseHeaders, bool useETagAsContinuation = false, IReadOnlyDictionary <string, QueryMetrics> queryMetrics = null, IClientSideRequestStatistics 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.disallowContinuationTokenMessage = disallowContinuationTokenMessage; this.ResponseLengthBytes = responseLengthBytes; }
/// <summary> /// Initializes cross partition query execution context by initializing the necessary document producers. /// </summary> /// <param name="collectionRid">The collection to drain from.</param> /// <param name="partitionKeyRanges">The partitions to target.</param> /// <param name="initialPageSize">The page size to start the document producers off with.</param> /// <param name="querySpecForInit">The query specification for the rewritten query.</param> /// <param name="targetRangeToContinuationMap">Map from partition to it's corresponding continuation token.</param> /// <param name="deferFirstPage">Whether or not we should defer the fetch of the first page from each partition.</param> /// <param name="filter">The filter to inject in the predicate.</param> /// <param name="filterCallback">The callback used to filter each partition.</param> /// <param name="token">The cancellation token.</param> /// <returns>A task to await on.</returns> protected async Task InitializeAsync( string collectionRid, IReadOnlyList <PartitionKeyRange> partitionKeyRanges, int initialPageSize, SqlQuerySpec querySpecForInit, Dictionary <string, string> targetRangeToContinuationMap, bool deferFirstPage, string filter, Func <DocumentProducerTree, Task> filterCallback, CancellationToken token) { CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); INameValueCollection requestHeaders = await this.CreateCommonHeadersAsync(this.GetFeedOptions(null)); this.TraceInformation(string.Format( CultureInfo.InvariantCulture, "parallel~contextbase.initializeasync, queryspec {0}, maxbuffereditemcount: {1}, target partitionkeyrange count: {2}, maximumconcurrencylevel: {3}, documentproducer initial page size {4}", JsonConvert.SerializeObject(this.querySpec, DefaultJsonSerializationSettings.Value), this.actualMaxBufferedItemCount, partitionKeyRanges.Count, this.comparableTaskScheduler.MaximumConcurrencyLevel, initialPageSize)); List <DocumentProducerTree> documentProducerTrees = new List <DocumentProducerTree>(); foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges) { string initialContinuationToken = (targetRangeToContinuationMap != null && targetRangeToContinuationMap.ContainsKey(partitionKeyRange.Id)) ? targetRangeToContinuationMap[partitionKeyRange.Id] : null; DocumentProducerTree documentProducerTree = new DocumentProducerTree( partitionKeyRange, //// Create Document Service Request callback (pkRange, continuationToken, pageSize) => { INameValueCollection headers = requestHeaders.Clone(); headers[HttpConstants.HttpHeaders.Continuation] = continuationToken; headers[HttpConstants.HttpHeaders.PageSize] = pageSize.ToString(CultureInfo.InvariantCulture); return(this.CreateDocumentServiceRequest( headers, querySpecForInit, pkRange, collectionRid)); }, this.ExecuteRequestLazyAsync, //// Retry policy callback () => new NonRetriableInvalidPartitionExceptionRetryPolicy(collectionCache, this.Client.ResetSessionTokenRetryPolicy.GetRequestPolicy()), this.OnDocumentProducerTreeCompleteFetching, this.documentProducerForest.Comparer as IComparer <DocumentProducerTree>, this.equalityComparer, this.Client, deferFirstPage, collectionRid, initialPageSize, initialContinuationToken); documentProducerTree.Filter = filter; // Prefetch if necessary, and populate consume queue. if (this.CanPrefetch) { this.TryScheduleFetch(documentProducerTree); } documentProducerTrees.Add(documentProducerTree); } // Using loop fisson so that we can load the document producers in parallel foreach (DocumentProducerTree documentProducerTree in documentProducerTrees) { if (!deferFirstPage) { await documentProducerTree.MoveNextIfNotSplitAsync(token); } if (filterCallback != null) { await filterCallback(documentProducerTree); } if (documentProducerTree.HasMoreResults) { this.documentProducerForest.Enqueue(documentProducerTree); } } }
protected async Task RepairContextAsync( string collectionRid, int currentDocumentProducerIndex, Func <DocumentProducer <T>, int> taskPriorityFunc, IReadOnlyList <PartitionKeyRange> replacementRanges, SqlQuerySpec querySpecForRepair, Action callback = null) { CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); INameValueCollection requestHeaders = await this.CreateCommonHeadersAsync(this.GetFeedOptions(null)); this.DocumentProducers.Capacity = this.DocumentProducers.Count + replacementRanges.Count - 1; DocumentProducer <T> replacedDocumentProducer = this.DocumentProducers[currentDocumentProducerIndex]; DefaultTrace.TraceInformation(string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {5} | Parallel~ContextBase.RepairContextAsync, MaxBufferedItemCount: {1}, Replacement PartitionKeyRange Count: {2}, MaximumConcurrencyLevel: {3}, DocumentProducer Initial Page Size {4}", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), this.actualMaxBufferedItemCount, replacementRanges.Count, this.TaskScheduler.MaximumConcurrencyLevel, replacedDocumentProducer.PageSize, this.CorrelatedActivityId)); int index = currentDocumentProducerIndex + 1; foreach (PartitionKeyRange range in replacementRanges) { this.DocumentProducers.Insert( index++, new DocumentProducer <T>( this.TaskScheduler, (continuationToken, pageSize) => { INameValueCollection headers = requestHeaders.Clone(); headers[HttpConstants.HttpHeaders.Continuation] = continuationToken; headers[HttpConstants.HttpHeaders.PageSize] = pageSize.ToString(CultureInfo.InvariantCulture); return(this.CreateDocumentServiceRequest( headers, querySpecForRepair, range, collectionRid)); }, range, taskPriorityFunc, this.ExecuteRequestAsync <T>, () => new NonRetriableInvalidPartitionExceptionRetryPolicy(collectionCache, this.Client.RetryPolicy.GetRequestPolicy()), this.OnDocumentProducerCompleteFetching, this.CorrelatedActivityId, replacedDocumentProducer.PageSize, replacedDocumentProducer.CurrentBackendContinuationToken)); } this.DocumentProducers.RemoveAt(currentDocumentProducerIndex); if (callback != null) { callback(); } if (this.ShouldPrefetch) { for (int i = 0; i < replacementRanges.Count; i++) { this.DocumentProducers[i + currentDocumentProducerIndex].TryScheduleFetch(); } } if (this.CurrentContinuationTokens.Remove(replacedDocumentProducer)) { for (int i = 0; i < replacementRanges.Count; ++i) { this.CurrentContinuationTokens[this.DocumentProducers[currentDocumentProducerIndex + i]] = replacedDocumentProducer.CurrentBackendContinuationToken; } } }