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)); } }
private void OnDocumentProducerCompleteFetching( DocumentProducer <T> producer, int size, double resourceUnitUsage, QueryMetrics queryMetrics, long responseLengthBytes, CancellationToken token) { // Update charge and states this.chargeTracker.AddCharge(resourceUnitUsage); Interlocked.Add(ref this.totalBufferedItems, size); Interlocked.Increment(ref this.totalRequestRoundTrips); this.IncrementResponseLengthBytes(responseLengthBytes); this.partitionedQueryMetrics.Add(Tuple.Create(producer.TargetRange.Id, queryMetrics)); //Check to see if we can buffer more item long countToAdd = size - this.FreeItemSpace; if (countToAdd > 0 && this.actualMaxBufferedItemCount < MaxixmumDynamicMaxBufferedItemCountValue - countToAdd) { DefaultTrace.TraceVerbose(string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {4} | Id: {1}, increasing MaxBufferedItemCount {2} by {3}.", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), producer.TargetRange.Id, this.actualMaxBufferedItemCount, countToAdd, this.CorrelatedActivityId)); countToAdd += this.actualMaxBufferedItemCount; } // Adjust max DoP if necessary this.AdjustTaskSchedulerMaximumConcurrencyLevel(); // Fetch again if necessary if (!producer.FetchedAll) { if (producer.PageSize < this.actualMaxPageSize) { producer.PageSize = Math.Min((long)(producer.PageSize * DynamicPageSizeAdjustmentFactor), this.actualMaxPageSize); Debug.Assert(producer.PageSize >= 0 && producer.PageSize <= int.MaxValue, string.Format("producer.PageSize is invalid at {0}", producer.PageSize)); } if (this.ShouldPrefetch && this.FreeItemSpace - producer.NormalizedPageSize > 0) { producer.TryScheduleFetch(); } } DefaultTrace.TraceVerbose(string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {5} | Id: {1}, size: {2}, resourceUnitUsage: {3}, taskScheduler.CurrentRunningTaskCount: {4}", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), producer.TargetRange.Id, size, resourceUnitUsage, this.TaskScheduler.CurrentRunningTaskCount, this.CorrelatedActivityId)); }