public async Task ReadFeedAsync() { int numItems = 100; IDocumentContainer documentContainer = await this.CreateDocumentContainerAsync(numItems); CrossPartitionReadFeedAsyncEnumerator enumerator = CrossPartitionReadFeedAsyncEnumerator.Create( documentContainer, new QueryRequestOptions(), new CrossFeedRangeState <ReadFeedState>(ReadFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates), pageSize: 10, cancellationToken: default); int numChildren = 1; // One extra since we need to read one past the last user page to get the null continuation. Trace rootTrace; using (rootTrace = Trace.GetRootTrace("Cross Partition Read Feed")) { while (await enumerator.MoveNextAsync(rootTrace)) { numChildren++; } } string traceString = TraceWriter.TraceToText(rootTrace); Console.WriteLine(traceString); Assert.AreEqual(numChildren, rootTrace.Children.Count); }
public IAsyncEnumerator <TryCatch <ReadFeedPage> > GetAsyncEnumerator(CancellationToken cancellationToken = default) { CrossFeedRangeState <ReadFeedState> innerState = new CrossFeedRangeState <ReadFeedState>(this.state.FeedRangeStates); CrossPartitionReadFeedAsyncEnumerator innerEnumerator = CrossPartitionReadFeedAsyncEnumerator.Create( this.documentContainer, innerState, this.readFeedPaginationOptions, cancellationToken); return(new ReadFeedCrossFeedRangeAsyncEnumerator(innerEnumerator)); }
public ReadFeedIteratorCore( IDocumentContainer documentContainer, string continuationToken, ReadFeedPaginationOptions readFeedPaginationOptions, QueryRequestOptions queryRequestOptions, CancellationToken cancellationToken) { this.queryRequestOptions = queryRequestOptions; readFeedPaginationOptions ??= ReadFeedPaginationOptions.Default; if (!string.IsNullOrEmpty(continuationToken)) { bool isNewArrayFormat = (continuationToken.Length >= 2) && (continuationToken[0] == '[') && (continuationToken[continuationToken.Length - 1] == ']'); if (!isNewArrayFormat) { // One of the two older formats if (!FeedRangeContinuation.TryParse(continuationToken, out FeedRangeContinuation feedRangeContinuation)) { // Backward compatible with old format feedRangeContinuation = new FeedRangeCompositeContinuation( containerRid: string.Empty, FeedRangeEpk.FullRange, new List <Documents.Routing.Range <string> >() { new Documents.Routing.Range <string>( Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, isMinInclusive: true, isMaxInclusive: false) }, continuationToken); } // need to massage it a little List <CosmosElement> feedRangeStates = new List <CosmosElement>(); string oldContinuationFormat = feedRangeContinuation.ToString(); if (feedRangeContinuation.FeedRange is FeedRangePartitionKey feedRangePartitionKey) { CosmosObject cosmosObject = CosmosObject.Parse(oldContinuationFormat); CosmosArray continuations = (CosmosArray)cosmosObject["Continuation"]; if (continuations.Count != 1) { throw new InvalidOperationException("Expected only one continuation for partition key queries"); } CosmosElement continuation = continuations[0]; CosmosObject continuationObject = (CosmosObject)continuation; CosmosElement token = continuationObject["token"]; ReadFeedState state; if (token is CosmosNull) { state = ReadFeedState.Beginning(); } else { CosmosString tokenAsString = (CosmosString)token; state = ReadFeedState.Continuation(CosmosElement.Parse(tokenAsString.Value)); } FeedRangeState <ReadFeedState> feedRangeState = new FeedRangeState <ReadFeedState>(feedRangePartitionKey, state); feedRangeStates.Add(ReadFeedFeedRangeStateSerializer.ToCosmosElement(feedRangeState)); } else { CosmosObject cosmosObject = CosmosObject.Parse(oldContinuationFormat); CosmosArray continuations = (CosmosArray)cosmosObject["Continuation"]; foreach (CosmosElement continuation in continuations) { CosmosObject continuationObject = (CosmosObject)continuation; CosmosObject rangeObject = (CosmosObject)continuationObject["range"]; string min = ((CosmosString)rangeObject["min"]).Value; string max = ((CosmosString)rangeObject["max"]).Value; CosmosElement token = continuationObject["token"]; FeedRangeInternal feedRange = new FeedRangeEpk(new Documents.Routing.Range <string>(min, max, isMinInclusive: true, isMaxInclusive: false)); ReadFeedState state; if (token is CosmosNull) { state = ReadFeedState.Beginning(); } else { CosmosString tokenAsString = (CosmosString)token; state = ReadFeedState.Continuation(CosmosElement.Parse(tokenAsString.Value)); } FeedRangeState <ReadFeedState> feedRangeState = new FeedRangeState <ReadFeedState>(feedRange, state); feedRangeStates.Add(ReadFeedFeedRangeStateSerializer.ToCosmosElement(feedRangeState)); } } CosmosArray cosmosArrayContinuationTokens = CosmosArray.Create(feedRangeStates); continuationToken = cosmosArrayContinuationTokens.ToString(); } } TryCatch <ReadFeedCrossFeedRangeState> monadicReadFeedState; if (continuationToken == null) { FeedRange feedRange; if ((this.queryRequestOptions != null) && this.queryRequestOptions.PartitionKey.HasValue) { feedRange = new FeedRangePartitionKey(this.queryRequestOptions.PartitionKey.Value); } else if ((this.queryRequestOptions != null) && (this.queryRequestOptions.FeedRange != null)) { feedRange = this.queryRequestOptions.FeedRange; } else { feedRange = FeedRangeEpk.FullRange; } monadicReadFeedState = TryCatch <ReadFeedCrossFeedRangeState> .FromResult(ReadFeedCrossFeedRangeState.CreateFromBeginning(feedRange)); } else { monadicReadFeedState = ReadFeedCrossFeedRangeState.Monadic.Parse(continuationToken); } if (monadicReadFeedState.Failed) { this.monadicEnumerator = TryCatch <CrossPartitionReadFeedAsyncEnumerator> .FromException(monadicReadFeedState.Exception); } else { this.monadicEnumerator = TryCatch <CrossPartitionReadFeedAsyncEnumerator> .FromResult( CrossPartitionReadFeedAsyncEnumerator.Create( documentContainer, new CrossFeedRangeState <ReadFeedState>(monadicReadFeedState.Result.FeedRangeStates), readFeedPaginationOptions, cancellationToken)); } this.hasMoreResults = true; }
public async Task ScenariosAsync() { List <Input> inputs = new List <Input>(); int startLineNumber; int endLineNumber; //---------------------------------------------------------------- // ReadFeed //---------------------------------------------------------------- { startLineNumber = GetLineNumber(); int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); CrossPartitionReadFeedAsyncEnumerator enumerator = CrossPartitionReadFeedAsyncEnumerator.Create( documentContainer, new CrossFeedRangeState <ReadFeedState>(ReadFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates), new ReadFeedPaginationOptions(pageSizeHint: 10), cancellationToken: default); int numChildren = 1; // One extra since we need to read one past the last user page to get the null continuation. TraceForBaselineTesting rootTrace; using (rootTrace = TraceForBaselineTesting.GetRootTrace()) { while (await enumerator.MoveNextAsync(rootTrace)) { numChildren++; } } Assert.AreEqual(numChildren, rootTrace.Children.Count); endLineNumber = GetLineNumber(); inputs.Add(new Input("ReadFeed", rootTrace, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- //---------------------------------------------------------------- // ChangeFeed //---------------------------------------------------------------- { startLineNumber = GetLineNumber(); int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create( documentContainer, new CrossFeedRangeState <ChangeFeedState>( ChangeFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates), new ChangeFeedPaginationOptions( ChangeFeedMode.Incremental, pageSizeHint: int.MaxValue), cancellationToken: default); int numChildren = 0; TraceForBaselineTesting rootTrace; using (rootTrace = TraceForBaselineTesting.GetRootTrace()) { while (await enumerator.MoveNextAsync(rootTrace)) { numChildren++; if (enumerator.Current.Result.Page is ChangeFeedNotModifiedPage) { break; } } } Assert.AreEqual(numChildren, rootTrace.Children.Count); endLineNumber = GetLineNumber(); inputs.Add(new Input("ChangeFeed", rootTrace, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- //---------------------------------------------------------------- // Query //---------------------------------------------------------------- { startLineNumber = GetLineNumber(); int numItems = 100; IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems); IQueryPipelineStage pipelineStage = CreatePipeline(documentContainer, "SELECT * FROM c", pageSize: 10); TraceForBaselineTesting rootTrace; int numChildren = 1; // One extra since we need to read one past the last user page to get the null continuation. using (rootTrace = TraceForBaselineTesting.GetRootTrace()) { while (await pipelineStage.MoveNextAsync(rootTrace)) { numChildren++; } } Assert.AreEqual(numChildren, rootTrace.Children.Count); endLineNumber = GetLineNumber(); inputs.Add(new Input("Query", rootTrace, startLineNumber, endLineNumber)); } //---------------------------------------------------------------- this.ExecuteTestSuite(inputs); }