Esempio n. 1
0
 /// <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;
        }
Esempio n. 3
0
        /// <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;
        }
Esempio n. 4
0
        /// <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;
        }