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); }
public override async Task <FeedResponse <object> > DrainAsync(int maxElements, CancellationToken token) { List <object> result = new List <object>(); List <Uri> replicaUris = new List <Uri>(); ClientSideRequestStatistics requestStats = new ClientSideRequestStatistics(); while (!this.IsDone) { DocumentProducer <object> currentDocumentProducer = base.DocumentProducers[this.currentDocumentProducerIndex]; if (currentDocumentProducer.IsAtContinuationBoundary) { if (maxElements - result.Count < currentDocumentProducer.ItemsTillNextContinuationBoundary) { break; } base.CurrentContinuationTokens[currentDocumentProducer] = currentDocumentProducer.ResponseContinuation; result.Add(currentDocumentProducer.Current); if (currentDocumentProducer.RequestStatistics != null) { replicaUris.AddRange(currentDocumentProducer.RequestStatistics.ContactedReplicas); } while (currentDocumentProducer.ItemsTillNextContinuationBoundary > 1) { bool hasMoreResults = await currentDocumentProducer.MoveNextAsync(token); Debug.Assert(hasMoreResults, "Expect hasMoreResults be true."); result.Add(currentDocumentProducer.Current); } } if (!await this.TryMoveNextProducerAsync(currentDocumentProducer, token)) { ++this.currentDocumentProducerIndex; if (this.currentDocumentProducerIndex < base.DocumentProducers.Count && !base.CurrentContinuationTokens.ContainsKey(base.DocumentProducers[this.currentDocumentProducerIndex])) { base.CurrentContinuationTokens[base.DocumentProducers[this.currentDocumentProducerIndex]] = null; } continue; } if (maxElements >= int.MaxValue && result.Count > this.ActualMaxBufferedItemCount) { break; } } this.ReduceTotalBufferedItems(result.Count); requestStats.ContactedReplicas.AddRange(replicaUris); return(new FeedResponse <object>(result, result.Count, this.ResponseHeaders, requestStats, this.GetAndResetResponseLengthBytes())); }
protected async Task <bool> TryMoveNextProducerAsync( DocumentProducer <T> producer, Func <DocumentProducer <T>, Task <DocumentProducer <T> > > producerRepairCallback, CancellationToken cancellationToken) { bool movedNext = false; DocumentProducer <T> currentProducer = producer; while (true) { bool needRefreshedPartitionKeyRangeCache = false; try { movedNext = await currentProducer.MoveNextAsync(cancellationToken); } catch (DocumentClientException ex) { if (!(needRefreshedPartitionKeyRangeCache = base.NeedPartitionKeyRangeCacheRefresh(ex))) { throw; } } if (needRefreshedPartitionKeyRangeCache) { currentProducer = await producerRepairCallback(currentProducer); } else { break; } } if (!movedNext) { this.CurrentContinuationTokens.Remove(currentProducer); } return(movedNext); }
private async Task FilterAsync( DocumentProducer <OrderByQueryResult> producer, SortOrder[] sortOrders, OrderByContinuationToken continuationToken, CancellationToken cancellationToken) { ResourceId continuationRid; if (!ResourceId.TryParse(continuationToken.Rid, out continuationRid)) { DefaultTrace.TraceWarning( string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {1}, ActivityId: {2} | Invalid Rid in the continuation token {3} for OrderBy~Context.", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), this.CorrelatedActivityId, this.ActivityId, continuationToken.CompositeToken.Token)); throw new BadRequestException(RMResources.InvalidContinuationToken); } Dictionary <string, ResourceId> resourceIds = new Dictionary <string, ResourceId>(); int itemToSkip = continuationToken.SkipCount; bool continuationRidVerified = false; while (true) { OrderByQueryResult orderByResult = (OrderByQueryResult)producer.Current; int cmp = 0; for (int i = 0; i < sortOrders.Length; ++i) { cmp = ItemComparer.Instance.Compare( continuationToken.OrderByItems[i].GetItem(), orderByResult.OrderByItems[i].GetItem()); if (cmp != 0) { cmp = sortOrders[i] != SortOrder.Descending ? cmp : -cmp; break; } } if (cmp < 0) { break; } if (cmp == 0) { ResourceId rid; if (!resourceIds.TryGetValue(orderByResult.Rid, out rid)) { if (!ResourceId.TryParse(orderByResult.Rid, out rid)) { DefaultTrace.TraceWarning( string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {1}, ActivityId: {2} | Invalid Rid in the continuation token {3} for OrderBy~Context.", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), this.CorrelatedActivityId, this.ActivityId, continuationToken.CompositeToken.Token)); throw new BadRequestException(RMResources.InvalidContinuationToken); } resourceIds.Add(orderByResult.Rid, rid); } if (!continuationRidVerified) { if (continuationRid.Database != rid.Database || continuationRid.DocumentCollection != rid.DocumentCollection) { DefaultTrace.TraceWarning( string.Format( CultureInfo.InvariantCulture, "{0}, CorrelatedActivityId: {1}, ActivityId: {2} | Invalid Rid in the continuation token {3} for OrderBy~Context.", DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), this.CorrelatedActivityId, this.ActivityId, continuationToken.CompositeToken.Token)); throw new BadRequestException(RMResources.InvalidContinuationToken); } continuationRidVerified = true; } cmp = continuationRid.Document.CompareTo(rid.Document); if (sortOrders[sortOrders.Length - 1] == SortOrder.Descending) { cmp = -cmp; } if (cmp < 0 || (cmp == 0 && itemToSkip-- <= 0)) { break; } } if (!await producer.MoveNextAsync(cancellationToken)) { break; } } }
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)); } }