/// <summary> /// Callback to create a child document producer tree based on the partition key range. /// </summary> /// <param name="queryContext">request context</param> /// <param name="querySpecForInit">query spec for initialization</param> /// <param name="produceAsyncCompleteCallback">Callback to invoke once a fetch finishes.</param> /// <param name="itemProducerTreeComparer">Comparer to determine, which tree to produce from.</param> /// <param name="equalityComparer">Comparer to see if we need to return the continuation token for a partition.</param> /// <param name="testFlags">Test flags.</param> /// <param name="deferFirstPage">Whether or not to defer fetching the first page.</param> /// <param name="collectionRid">The collection to drain from.</param> /// <param name="initialPageSize">The initial page size.</param> /// <returns>A function that given a partition key range and continuation token will create a document producer.</returns> private static Func <Documents.PartitionKeyRange, string, ItemProducerTree> CreateItemProducerTreeCallback( CosmosQueryContext queryContext, SqlQuerySpec querySpecForInit, ProduceAsyncCompleteDelegate produceAsyncCompleteCallback, IComparer <ItemProducerTree> itemProducerTreeComparer, IEqualityComparer <CosmosElement> equalityComparer, TestInjections testFlags, bool deferFirstPage, string collectionRid, long initialPageSize = 50) { return((partitionKeyRange, continuationToken) => { return new ItemProducerTree( queryContext, querySpecForInit, partitionKeyRange, produceAsyncCompleteCallback, itemProducerTreeComparer, equalityComparer, testFlags, deferFirstPage, collectionRid, initialPageSize, continuationToken); }); }
/// <summary> /// Initializes a new instance of the ItemProducer class. /// </summary> /// <param name="queryContext">request context</param> /// <param name="querySpecForInit">query spec for initialization</param> /// <param name="partitionKeyRange">The partition key range.</param> /// <param name="produceAsyncCompleteCallback">The callback to call once you are done fetching.</param> /// <param name="equalityComparer">The comparer to use to determine whether the producer has seen a new document.</param> /// <param name="testFlags">Flags used to help faciliate testing.</param> /// <param name="initialPageSize">The initial page size.</param> /// <param name="initialContinuationToken">The initial continuation token.</param> public ItemProducer( CosmosQueryContext queryContext, SqlQuerySpec querySpecForInit, PartitionKeyRange partitionKeyRange, ProduceAsyncCompleteDelegate produceAsyncCompleteCallback, IEqualityComparer <CosmosElement> equalityComparer, TestInjections testFlags, long initialPageSize = 50, string initialContinuationToken = null) { this.bufferedPages = new AsyncCollection <QueryResponseCore>(); // We use a binary semaphore to get the behavior of a mutex, // since fetching documents from the backend using a continuation token is a critical section. this.fetchSemaphore = new SemaphoreSlim(1, 1); this.queryContext = queryContext; this.querySpecForInit = querySpecForInit; this.PartitionKeyRange = partitionKeyRange ?? throw new ArgumentNullException(nameof(partitionKeyRange)); this.produceAsyncCompleteCallback = produceAsyncCompleteCallback ?? throw new ArgumentNullException(nameof(produceAsyncCompleteCallback)); this.equalityComparer = equalityComparer ?? throw new ArgumentNullException(nameof(equalityComparer)); this.pageSize = initialPageSize; this.CurrentContinuationToken = initialContinuationToken; this.BackendContinuationToken = initialContinuationToken; this.PreviousContinuationToken = initialContinuationToken; if (!string.IsNullOrEmpty(initialContinuationToken)) { this.hasStartedFetching = true; this.IsActive = true; } this.testFlags = testFlags; this.HasMoreResults = true; }
/// <summary> /// Initializes a new instance of the ItemProducer class. /// </summary> /// <param name="queryContext">request context</param> /// <param name="querySpecForInit">query spec for initialization</param> /// <param name="partitionKeyRange">The partition key range.</param> /// <param name="createRetryPolicyFunc">The callback to create the retry policy.</param> /// <param name="produceAsyncCompleteCallback">The callback to call once you are done fetching.</param> /// <param name="equalityComparer">The comparer to use to determine whether the producer has seen a new document.</param> /// <param name="initialPageSize">The initial page size.</param> /// <param name="initialContinuationToken">The initial continuation token.</param> public ItemProducer( CosmosQueryContext queryContext, SqlQuerySpec querySpecForInit, PartitionKeyRange partitionKeyRange, Func <IDocumentClientRetryPolicy> createRetryPolicyFunc, ProduceAsyncCompleteDelegate produceAsyncCompleteCallback, IEqualityComparer <CosmosElement> equalityComparer, long initialPageSize = 50, string initialContinuationToken = null) { this.bufferedPages = new AsyncCollection <TryMonad <FeedResponse <CosmosElement> > >(); // We use a binary semaphore to get the behavior of a mutex, // since fetching documents from the backend using a continuation token is a critical section. this.fetchSemaphore = new SemaphoreSlim(1, 1); if (partitionKeyRange == null) { throw new ArgumentNullException(nameof(partitionKeyRange)); } if (createRetryPolicyFunc == null) { throw new ArgumentNullException(nameof(createRetryPolicyFunc)); } if (produceAsyncCompleteCallback == null) { throw new ArgumentNullException(nameof(produceAsyncCompleteCallback)); } if (equalityComparer == null) { throw new ArgumentNullException(nameof(equalityComparer)); } this.queryContext = queryContext; this.querySpecForInit = querySpecForInit; this.PartitionKeyRange = partitionKeyRange; this.createRetryPolicyFunc = createRetryPolicyFunc; this.produceAsyncCompleteCallback = produceAsyncCompleteCallback; this.equalityComparer = equalityComparer; this.pageSize = initialPageSize; this.currentContinuationToken = initialContinuationToken; this.BackendContinuationToken = initialContinuationToken; this.PreviousContinuationToken = initialContinuationToken; if (!string.IsNullOrEmpty(initialContinuationToken)) { this.hasStartedFetching = true; this.IsActive = true; } this.fetchSchedulingMetrics = new SchedulingStopwatch(); this.fetchSchedulingMetrics.Ready(); this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator(); this.HasMoreResults = true; }
/// <summary> /// Initializes a new instance of the ItemProducerTree class. /// </summary> /// <param name="queryContext">query context.</param> /// <param name="querySpecForInit">query spec init.</param> /// <param name="partitionKeyRange">The partition key range.</param> /// <param name="produceAsyncCompleteCallback">Callback to invoke once a fetch finishes.</param> /// <param name="itemProducerTreeComparer">Comparer to determine, which tree to produce from.</param> /// <param name="equalityComparer">Comparer to see if we need to return the continuation token for a partition.</param> /// <param name="testSettings">Test flags.</param> /// <param name="deferFirstPage">Whether or not to defer fetching the first page.</param> /// <param name="collectionRid">The collection to drain from.</param> /// <param name="initialPageSize">The initial page size.</param> /// <param name="initialContinuationToken">The initial continuation token.</param> public ItemProducerTree( CosmosQueryContext queryContext, SqlQuerySpec querySpecForInit, Documents.PartitionKeyRange partitionKeyRange, ProduceAsyncCompleteDelegate produceAsyncCompleteCallback, IComparer <ItemProducerTree> itemProducerTreeComparer, IEqualityComparer <CosmosElement> equalityComparer, TestInjections testSettings, bool deferFirstPage, string collectionRid, long initialPageSize = 50, string initialContinuationToken = null) { if (queryContext == null) { throw new ArgumentNullException($"{nameof(queryContext)}"); } if (itemProducerTreeComparer == null) { throw new ArgumentNullException($"{nameof(itemProducerTreeComparer)}"); } if (produceAsyncCompleteCallback == null) { throw new ArgumentNullException($"{nameof(produceAsyncCompleteCallback)}"); } if (itemProducerTreeComparer == null) { throw new ArgumentNullException($"{nameof(itemProducerTreeComparer)}"); } if (equalityComparer == null) { throw new ArgumentNullException($"{nameof(equalityComparer)}"); } if (string.IsNullOrEmpty(collectionRid)) { throw new ArgumentException($"{nameof(collectionRid)} can not be null or empty."); } this.Root = new ItemProducer( queryContext, querySpecForInit, partitionKeyRange, (itemsBuffered, resourceUnitUsage, diagnostics, requestLength, token) => produceAsyncCompleteCallback(this, itemsBuffered, resourceUnitUsage, diagnostics, requestLength, token), equalityComparer, testSettings, initialPageSize, initialContinuationToken); this.queryClient = queryContext.QueryClient; this.children = new PriorityQueue <ItemProducerTree>(itemProducerTreeComparer, true); this.deferFirstPage = deferFirstPage; this.collectionRid = collectionRid; this.createItemProducerTreeCallback = ItemProducerTree.CreateItemProducerTreeCallback( queryContext, querySpecForInit, produceAsyncCompleteCallback, itemProducerTreeComparer, equalityComparer, testSettings, deferFirstPage, collectionRid, initialPageSize); this.executeWithSplitProofingSemaphore = new SemaphoreSlim(1, 1); }
public DocumentProducer( ComparableTaskScheduler taskScheduler, Func <string, int, DocumentServiceRequest> createRequestFunc, PartitionKeyRange targetRange, Func <DocumentProducer <T>, int> taskPriorityFunc, Func <DocumentServiceRequest, CancellationToken, Task <FeedResponse <T> > > executeRequestFunc, Func <IDocumentClientRetryPolicy> createRetryPolicyFunc, ProduceAsyncCompleteDelegate produceAsyncCompleteCallback, Guid correlatedActivityId, long initialPageSize = 50, string initialContinuationToken = null) { if (taskScheduler == null) { throw new ArgumentNullException("taskScheduler"); } if (createRequestFunc == null) { throw new ArgumentNullException("documentServiceRequest"); } if (targetRange == null) { throw new ArgumentNullException("targetRange"); } if (taskPriorityFunc == null) { throw new ArgumentNullException("taskPriorityFunc"); } if (executeRequestFunc == null) { throw new ArgumentNullException("executeRequestFunc"); } if (createRetryPolicyFunc == null) { throw new ArgumentNullException("createRetryPolicyFunc"); } if (produceAsyncCompleteCallback == null) { throw new ArgumentNullException("produceAsyncCallback"); } this.taskScheduler = taskScheduler; this.itemBuffer = new AsyncCollection <FetchResult>(); this.createRequestFunc = createRequestFunc; this.targetRange = targetRange; this.taskPriorityFunc = taskPriorityFunc; this.createRetryPolicyFunc = createRetryPolicyFunc; this.executeRequestFunc = executeRequestFunc; this.produceAsyncCompleteCallback = produceAsyncCompleteCallback; this.PageSize = initialPageSize; if ((int)this.PageSize < 0) { throw new ArithmeticException("page size is negative.."); } this.correlatedActivityId = correlatedActivityId; this.CurrentBackendContinuationToken = initialContinuationToken; this.moveNextSchedulingMetrics = new SchedulingStopwatch(); this.moveNextSchedulingMetrics.Ready(); this.fetchSchedulingMetrics = new SchedulingStopwatch(); this.fetchSchedulingMetrics.Ready(); this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator(this.targetRange.Id); this.fetchStateSemaphore = new SemaphoreSlim(1, 1); }
/// <summary> /// Initializes a new instance of the DocumentProducer class. /// </summary> /// <param name="partitionKeyRange">The partition key range.</param> /// <param name="createRequestFunc">The callback to create a request.</param> /// <param name="executeRequestFunc">The callback to execute the request.</param> /// <param name="createRetryPolicyFunc">The callback to create the retry policy.</param> /// <param name="produceAsyncCompleteCallback">The callback to call once you are done fetching.</param> /// <param name="equalityComparer">The comparer to use to determine whether the producer has seen a new document.</param> /// <param name="initialPageSize">The initial page size.</param> /// <param name="initialContinuationToken">The initial continuation token.</param> public DocumentProducer( PartitionKeyRange partitionKeyRange, Func <PartitionKeyRange, string, int, DocumentServiceRequest> createRequestFunc, Func <DocumentServiceRequest, CancellationToken, Task <FeedResponse <CosmosElement> > > executeRequestFunc, Func <IDocumentClientRetryPolicy> createRetryPolicyFunc, ProduceAsyncCompleteDelegate produceAsyncCompleteCallback, IEqualityComparer <CosmosElement> equalityComparer, long initialPageSize = 50, string initialContinuationToken = null) { this.bufferedPages = new AsyncCollection <FeedResponse <CosmosElement> >(); this.fetchSemaphore = new SemaphoreSlim(1, 1); if (partitionKeyRange == null) { throw new ArgumentNullException(nameof(partitionKeyRange)); } if (createRequestFunc == null) { throw new ArgumentNullException(nameof(createRequestFunc)); } if (executeRequestFunc == null) { throw new ArgumentNullException(nameof(executeRequestFunc)); } if (createRetryPolicyFunc == null) { throw new ArgumentNullException(nameof(createRetryPolicyFunc)); } if (produceAsyncCompleteCallback == null) { throw new ArgumentNullException(nameof(produceAsyncCompleteCallback)); } if (equalityComparer == null) { throw new ArgumentNullException(nameof(equalityComparer)); } this.PartitionKeyRange = partitionKeyRange; this.createRequestFunc = createRequestFunc; this.executeRequestFunc = executeRequestFunc; this.createRetryPolicyFunc = createRetryPolicyFunc; this.produceAsyncCompleteCallback = produceAsyncCompleteCallback; this.equalityComparer = equalityComparer; this.pageSize = initialPageSize; this.currentContinuationToken = initialContinuationToken; this.backendContinuationToken = initialContinuationToken; this.previousContinuationToken = initialContinuationToken; if (!string.IsNullOrEmpty(initialContinuationToken)) { this.hasStartedFetching = true; this.isActive = true; } this.fetchSchedulingMetrics = new SchedulingStopwatch(); this.fetchSchedulingMetrics.Ready(); this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator(this.PartitionKeyRange.Id); this.hasMoreResults = true; }