Example #1
0
        public async Task TestDelayedQueueTaskAsync()
        {
            ComparableTaskScheduler scheduler = new ComparableTaskScheduler();
            Task task = new Task(() =>
            {
                Assert.AreEqual(1, scheduler.CurrentRunningTaskCount);
            });
            Task delayedTask = new Task(() =>
            {
                Assert.AreEqual(1, scheduler.CurrentRunningTaskCount);
            });

            Assert.AreEqual(true, scheduler.TryQueueTask(new TestComparableTask(0, delayedTask), TimeSpan.FromMilliseconds(200)));
            Assert.AreEqual(false, scheduler.TryQueueTask(new TestComparableTask(0, delayedTask), TimeSpan.FromMilliseconds(200)));
            Assert.AreEqual(false, scheduler.TryQueueTask(new TestComparableTask(0, task)));
            Assert.AreEqual(true, scheduler.TryQueueTask(new TestComparableTask(1, task)));
            await Task.Delay(150);

            Assert.AreEqual(true, task.IsCompleted);
            Assert.AreEqual(false, delayedTask.IsCompleted);
            Assert.AreEqual(0, scheduler.CurrentRunningTaskCount);
            await Task.Delay(200);

            Assert.AreEqual(true, delayedTask.IsCompleted);
        }
        /// <summary>
        /// Initializes a new instance of the CosmosCrossPartitionQueryExecutionContext class.
        /// </summary>
        /// <param name="queryContext">Constructor parameters for the base class.</param>
        /// <param name="maxConcurrency">The max concurrency</param>
        /// <param name="maxBufferedItemCount">The max buffered item count</param>
        /// <param name="maxItemCount">Max item count</param>
        /// <param name="moveNextComparer">Comparer used to figure out that document producer tree to serve documents from next.</param>
        /// <param name="fetchPrioirtyFunction">The priority function to determine which partition to fetch documents from next.</param>
        /// <param name="equalityComparer">Used to determine whether we need to return the continuation token for a partition.</param>
        /// <param name="returnResultsInDeterministicOrder">Whether or not to return results in deterministic order.</param>
        /// <param name="testSettings">Test settings.</param>
        protected CosmosCrossPartitionQueryExecutionContext(
            CosmosQueryContext queryContext,
            int?maxConcurrency,
            int?maxItemCount,
            int?maxBufferedItemCount,
            IComparer <ItemProducerTree> moveNextComparer,
            Func <ItemProducerTree, int> fetchPrioirtyFunction,
            IEqualityComparer <CosmosElement> equalityComparer,
            bool returnResultsInDeterministicOrder,
            TestInjections testSettings)
        {
            if (moveNextComparer == null)
            {
                throw new ArgumentNullException(nameof(moveNextComparer));
            }

            this.queryContext            = queryContext ?? throw new ArgumentNullException(nameof(queryContext));
            this.queryClient             = queryContext.QueryClient ?? throw new ArgumentNullException(nameof(queryContext.QueryClient));
            this.itemProducerForest      = new PriorityQueue <ItemProducerTree>(moveNextComparer, isSynchronized: true);
            this.fetchPrioirtyFunction   = fetchPrioirtyFunction ?? throw new ArgumentNullException(nameof(fetchPrioirtyFunction));
            this.comparableTaskScheduler = new ComparableTaskScheduler(maxConcurrency.GetValueOrDefault(0));
            this.equalityComparer        = equalityComparer ?? throw new ArgumentNullException(nameof(equalityComparer));
            this.testSettings            = testSettings;
            this.requestChargeTracker    = new RequestChargeTracker();
            this.diagnosticsPages        = new ConcurrentBag <QueryPageDiagnostics>();
            this.actualMaxPageSize       = maxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalMaxItemCount);

            if (this.actualMaxPageSize < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be less than 0");
            }

            if (this.actualMaxPageSize > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be greater than int.MaxValue");
            }

            if (maxBufferedItemCount.HasValue)
            {
                this.actualMaxBufferedItemCount = maxBufferedItemCount.Value;
            }
            else
            {
                this.actualMaxBufferedItemCount = ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize;
            }

            if (this.actualMaxBufferedItemCount < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be less than 0");
            }

            if (this.actualMaxBufferedItemCount > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be greater than int.MaxValue");
            }

            this.CanPrefetch = maxConcurrency.HasValue && maxConcurrency.Value != 0;

            this.returnResultsInDeterministicOrder = returnResultsInDeterministicOrder;
        }
Example #3
0
        /// <summary>
        /// Initializes a new instance of the CosmosCrossPartitionQueryExecutionContext class.
        /// </summary>
        /// <param name="initParams">Constructor parameters for the base class.</param>
        /// <param name="moveNextComparer">Comparer used to figure out that document producer tree to serve documents from next.</param>
        /// <param name="fetchPrioirtyFunction">The priority function to determine which partition to fetch documents from next.</param>
        /// <param name="equalityComparer">Used to determine whether we need to return the continuation token for a partition.</param>
        protected CosmosCrossPartitionQueryExecutionContext(
            CosmosQueryContext initParams,
            IComparer <ItemProducerTree> moveNextComparer,
            Func <ItemProducerTree, int> fetchPrioirtyFunction,
            IEqualityComparer <CosmosElement> equalityComparer)
        {
            if (moveNextComparer == null)
            {
                throw new ArgumentNullException(nameof(moveNextComparer));
            }

            if (fetchPrioirtyFunction == null)
            {
                throw new ArgumentNullException(nameof(fetchPrioirtyFunction));
            }

            if (equalityComparer == null)
            {
                throw new ArgumentNullException(nameof(equalityComparer));
            }

            this.queryContext            = initParams;
            this.queryRequestOptions     = initParams.QueryRequestOptions;
            this.itemProducerForest      = new PriorityQueue <ItemProducerTree>(moveNextComparer, isSynchronized: true);
            this.fetchPrioirtyFunction   = fetchPrioirtyFunction;
            this.comparableTaskScheduler = new ComparableTaskScheduler(initParams.QueryRequestOptions.MaxConcurrency.GetValueOrDefault(0));
            this.equalityComparer        = equalityComparer;
            this.requestChargeTracker    = new RequestChargeTracker();
            this.partitionedQueryMetrics = new ConcurrentBag <Tuple <string, QueryMetrics> >();
            this.actualMaxPageSize       = this.queryRequestOptions.MaxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalMaxItemCount);

            if (this.actualMaxPageSize < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be less than 0");
            }

            if (this.actualMaxPageSize > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be greater than int.MaxValue");
            }

            if (this.queryRequestOptions.MaxBufferedItemCount.HasValue)
            {
                this.actualMaxBufferedItemCount = this.queryRequestOptions.MaxBufferedItemCount.Value;
            }
            else
            {
                this.actualMaxBufferedItemCount = ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize;
            }

            if (this.actualMaxBufferedItemCount < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be less than 0");
            }

            if (this.actualMaxBufferedItemCount > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be greater than int.MaxValue");
            }
        }
        public async Task TestOperationCanceledExceptionAsync()
        {
            int    seed = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            Random rand = new Random(seed);
            IDocumentClientRetryPolicy retryPolicy = new MockRetryPolicy(rand);
            ComparableTaskScheduler    scheduler   = new ComparableTaskScheduler(1);

            DocumentProducer <int> producer = new DocumentProducer <int>(
                scheduler,
                (continuation, pageSize) => null,
                new PartitionKeyRange {
                Id = "test", MinInclusive = "", MaxExclusive = "ff"
            },
                p => 0,
                (request, token) =>
            {
                scheduler.Stop();
                throw new Exception();
            },
                () => retryPolicy,
                (produer, size, ru, queryMetrics, token, length) => { },
                Guid.NewGuid()
                )
            {
                PageSize = 1000
            };

            await producer.MoveNextAsync(new CancellationTokenSource().Token);
        }
Example #5
0
 public void TestStop()
 {
     using ComparableTaskScheduler scheduler = new ComparableTaskScheduler();
     Assert.AreEqual(true, scheduler.TryQueueTask(new TestComparableTask(0, Task.FromResult(false))));
     scheduler.Stop();
     Assert.AreEqual(false, scheduler.TryQueueTask(new TestComparableTask(0, Task.FromResult(false))));
 }
Example #6
0
        public async Task SimpleTestAsync()
        {
            foreach (bool useConstructorToAddTasks in new[] { true, false })
            {
                List <Task> tasks = new List <Task>();
                int         maximumConcurrencyLevel = 10;

                for (int i = 0; i < maximumConcurrencyLevel; ++i)
                {
                    tasks.Add(new Task(() => { }));
                }

                await Task.Delay(1);

                foreach (Task task in tasks)
                {
                    Assert.AreEqual(false, task.IsCompleted);
                }

                ComparableTaskScheduler scheduler = null;
                try
                {
                    if (useConstructorToAddTasks)
                    {
                        scheduler = new ComparableTaskScheduler(
                            tasks.Select(task => new TestComparableTask(tasks.IndexOf(task), task)),
                            maximumConcurrencyLevel);
                    }
                    else
                    {
                        scheduler = new ComparableTaskScheduler(maximumConcurrencyLevel);
                        for (int i = 0; i < maximumConcurrencyLevel; ++i)
                        {
                            Assert.AreEqual(true, scheduler.TryQueueTask(new TestComparableTask(i, tasks[i])));
                        }
                    }

                    bool completionStatus = Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(10));
                    Assert.IsTrue(completionStatus);

                    foreach (Task task in tasks)
                    {
                        Assert.AreEqual(true, task.IsCompleted, $"Is overloaded constructor {useConstructorToAddTasks} and status {task.Status.ToString()}");
                    }
                }
                finally
                {
                    if (scheduler != null)
                    {
                        scheduler.Dispose();
                    }
                }
            }
        }
Example #7
0
        public void TestMaximumConcurrencyLevel()
        {
            using ComparableTaskScheduler firstScheduler = new ComparableTaskScheduler(10);
            Assert.AreEqual(10, firstScheduler.MaximumConcurrencyLevel);

            using ComparableTaskScheduler scheduler = new ComparableTaskScheduler();
            Assert.AreEqual(Environment.ProcessorCount, scheduler.MaximumConcurrencyLevel);

            scheduler.IncreaseMaximumConcurrencyLevel(1);
            Assert.AreEqual(Environment.ProcessorCount + 1, scheduler.MaximumConcurrencyLevel);

            try
            {
                scheduler.IncreaseMaximumConcurrencyLevel(-1);
                Assert.Fail("Expect ArgumentOutOfRangeException");
            }
            catch (ArgumentOutOfRangeException)
            {
            }
        }
Example #8
0
        /// <summary>
        /// Initializes a new instance of the CrossPartitionQueryExecutionContext class.
        /// </summary>
        /// <param name="initParams">Constructor parameters for the base class.</param>
        /// <param name="rewrittenQuery">
        /// Queries will get rewritten for different reasons.
        /// You can read more about this in the details from the concrete classes.
        /// </param>
        /// <param name="moveNextComparer">Comparer used to figure out that document producer tree to serve documents from next.</param>
        /// <param name="fetchPrioirtyFunction">The priority function to determine which partition to fetch documents from next.</param>
        /// <param name="equalityComparer">Used to determine whether we need to return the continuation token for a partition.</param>
        protected CrossPartitionQueryExecutionContext(
            DocumentQueryExecutionContextBase.InitParams initParams,
            string rewrittenQuery,
            IComparer <DocumentProducerTree> moveNextComparer,
            Func <DocumentProducerTree, int> fetchPrioirtyFunction,
            IEqualityComparer <CosmosElement> equalityComparer)
            : base(initParams)
        {
            if (!string.IsNullOrWhiteSpace(rewrittenQuery))
            {
                this.querySpec = new SqlQuerySpec(rewrittenQuery, this.QuerySpec.Parameters);
            }

            if (moveNextComparer == null)
            {
                throw new ArgumentNullException($"{nameof(moveNextComparer)} can not be null");
            }

            if (fetchPrioirtyFunction == null)
            {
                throw new ArgumentNullException($"{nameof(fetchPrioirtyFunction)} can not be null");
            }

            if (equalityComparer == null)
            {
                throw new ArgumentNullException($"{nameof(equalityComparer)} can not be null");
            }

            this.documentProducerForest  = new PriorityQueue <DocumentProducerTree>(moveNextComparer, isSynchronized: true);
            this.fetchPrioirtyFunction   = fetchPrioirtyFunction;
            this.comparableTaskScheduler = new ComparableTaskScheduler(initParams.FeedOptions.MaxDegreeOfParallelism);
            this.equalityComparer        = equalityComparer;
            this.requestChargeTracker    = new RequestChargeTracker();
            this.partitionedQueryMetrics = new ConcurrentBag <Tuple <string, QueryMetrics> >();
            this.actualMaxPageSize       = this.MaxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalMaxItemCount);
            if (this.actualMaxPageSize < 0)
            {
                throw new OverflowException("actualMaxPageSize should never be less than 0");
            }

            if (this.actualMaxPageSize > int.MaxValue)
            {
                throw new OverflowException("actualMaxPageSize should never be greater than int.MaxValue");
            }

            if (IsMaxBufferedItemCountSet(this.MaxBufferedItemCount))
            {
                this.actualMaxBufferedItemCount = this.MaxBufferedItemCount;
            }
            else
            {
                this.actualMaxBufferedItemCount = ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize;
            }

            if (this.actualMaxBufferedItemCount < 0)
            {
                throw new OverflowException("actualMaxBufferedItemCount should never be less than 0");
            }

            if (this.actualMaxBufferedItemCount > int.MaxValue)
            {
                throw new OverflowException("actualMaxBufferedItemCount should never be greater than int.MaxValue");
            }
        }
        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);
        }
        public async Task ConcurrentMoveNextTryScheduleTestAsync()
        {
            int    seed     = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            Random rand     = new Random(seed);
            int    maxValue = 100;
            int    trials   = 1000;
            int    maxTicks = 100;

            IEnumerable <int>          expectedValues = Enumerable.Range(1, maxValue);
            IDocumentClientRetryPolicy retryPolicy    = new MockRetryPolicy(rand);
            ComparableTaskScheduler    scheduler      = new ComparableTaskScheduler(1);

            for (int trial = 0; trial < trials; ++trial)
            {
                DocumentProducer <int> producer = new DocumentProducer <int>(
                    scheduler,
                    (continuation, pageSize) => DocumentServiceRequest.Create(
                        OperationType.Query,
                        "/dbs/db/colls/coll",
                        ResourceType.Document,
                        new MemoryStream(Encoding.UTF8.GetBytes(continuation)),
                        AuthorizationTokenType.PrimaryMasterKey,
                        new StringKeyValueCollection
                {
                    { HttpConstants.HttpHeaders.Continuation, continuation }
                }),
                    new PartitionKeyRange {
                    Id = "test", MinInclusive = "", MaxExclusive = "ff"
                },
                    p => 0,
                    (request, token) =>
                {
                    if (rand.Next(4) == 0)
                    {
                        throw new Exception();
                    }

                    if (rand.Next(10) == 0)
                    {
                        return(Task.FromResult(new FeedResponse <int>(new int[] { }, 0, request.Headers)));
                    }

                    using (StreamReader reader = new StreamReader(request.Body))
                    {
                        int value = int.Parse(reader.ReadToEnd()) + 1;
                        INameValueCollection headers = new StringKeyValueCollection
                        {
                            { HttpConstants.HttpHeaders.Continuation, value >= maxValue? null : value.ToString(CultureInfo.InvariantCulture) }
                        };
                        return(Task.FromResult(new FeedResponse <int>(new int[] { value }, 1, headers)));
                    }
                },
                    () => retryPolicy,
                    (produer, size, ru, queryMetrics, token, length) => { },
                    Guid.NewGuid(),
                    1000,
                    "0");

                Timer timer = new Timer(
                    (state) => producer.TryScheduleFetch(TimeSpan.FromTicks(rand.Next(maxTicks))),
                    null,
                    TimeSpan.FromTicks(rand.Next(maxTicks)),
                    TimeSpan.FromTicks(rand.Next(maxTicks)));

                List <int> actualValues             = new List <int>();
                CancellationTokenSource tokenSource = new CancellationTokenSource(5000);
                while (await producer.MoveNextAsync(tokenSource.Token))
                {
                    actualValues.Add(producer.Current);
                }

                Assert.AreEqual(
                    string.Join(", ", expectedValues),
                    string.Join(", ", actualValues),
                    string.Format(CultureInfo.InvariantCulture, "seed: {0}", seed));
            }
        }
Example #11
0
        protected ParallelDocumentQueryExecutionContextBase(
            IDocumentQueryClient client,
            ResourceType resourceTypeEnum,
            Type resourceType,
            Expression expression,
            FeedOptions feedOptions,
            string resourceLink,
            string rewrittenQuery,
            Guid correlatedActivityId,
            bool isContinuationExpected,
            bool getLazyFeedResponse,
            bool isDynamicPageSizeAllowed) :
            base(
                client,
                resourceTypeEnum,
                resourceType,
                expression,
                feedOptions,
                resourceLink,
                getLazyFeedResponse,
                correlatedActivityId)
        {
            this.DocumentProducers = new List <DocumentProducer <T> >();

            this.chargeTracker           = new RequestChargeTracker();
            this.groupedQueryMetrics     = new Dictionary <string, QueryMetrics>();
            this.partitionedQueryMetrics = new ConcurrentBag <Tuple <string, QueryMetrics> >();
            this.responseHeaders         = new StringKeyValueCollection();

            this.actualMaxBufferedItemCount            = Math.Max(this.MaxBufferedItemCount, ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize);
            this.currentAverageNumberOfRequestsPerTask = 1d;

            if (!string.IsNullOrEmpty(rewrittenQuery))
            {
                this.querySpec = new SqlQuerySpec(rewrittenQuery, this.QuerySpec.Parameters);
            }

            this.TaskScheduler                   = new ComparableTaskScheduler(this.GetCurrentMaximumAllowedConcurrentTasks(0));
            this.ShouldPrefetch                  = feedOptions.MaxDegreeOfParallelism != 0;
            this.IsContinuationExpected          = isContinuationExpected;
            this.DefaultContinuationToken        = Guid.NewGuid().ToString();
            this.InitializationSchedulingMetrics = new SchedulingStopwatch();
            this.InitializationSchedulingMetrics.Ready();
            this.CurrentContinuationTokens = new SortedList <DocumentProducer <T>, string>(
                Comparer <DocumentProducer <T> > .Create((producer1, producer2) => string.CompareOrdinal(producer1.TargetRange.MinInclusive, producer2.TargetRange.MinInclusive)));
            this.actualMaxPageSize = this.MaxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalMaxItemCount);

            if (this.actualMaxBufferedItemCount < 0)
            {
                throw new OverflowException("actualMaxBufferedItemCount should never be less than 0");
            }

            if (this.actualMaxBufferedItemCount > int.MaxValue)
            {
                throw new OverflowException("actualMaxBufferedItemCount should never be greater than int.MaxValue");
            }

            if (this.actualMaxPageSize < 0)
            {
                throw new OverflowException("actualMaxPageSize should never be less than 0");
            }

            if (this.actualMaxPageSize > int.MaxValue)
            {
                throw new OverflowException("actualMaxPageSize should never be greater than int.MaxValue");
            }
        }