Пример #1
0
        public async Task SomeChangesAsync()
        {
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 1);

            CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create(
                documentContainer,
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions(),
                new CrossFeedRangeState <ChangeFeedState>(
                    new FeedRangeState <ChangeFeedState>[]
            {
                new FeedRangeState <ChangeFeedState>(FeedRangeEpk.FullRange, ChangeFeedState.Beginning())
            }),
                cancellationToken: default);

            // First page should be true and skip the 304 not modified
            Assert.IsTrue(await enumerator.MoveNextAsync());
            Assert.IsTrue(enumerator.Current.Succeeded);
            Assert.IsTrue(enumerator.Current.Result.Page is ChangeFeedSuccessPage);

            // Second page should surface up the 304
            Assert.IsTrue(await enumerator.MoveNextAsync());
            Assert.IsTrue(enumerator.Current.Succeeded);
            Assert.IsTrue(enumerator.Current.Result.Page is ChangeFeedNotModifiedPage);
        }
Пример #2
0
        private static async Task <int> DrainWithUntilNotModifiedWithContinuationTokens(
            IDocumentContainer documentContainer,
            CrossPartitionChangeFeedAsyncEnumerator enumerator)
        {
            List <CosmosElement> globalChanges = new List <CosmosElement>();

            while (true)
            {
                if (!await enumerator.MoveNextAsync())
                {
                    throw new InvalidOperationException();
                }

                Assert.IsTrue(enumerator.Current.Succeeded);

                if (!(enumerator.Current.Result is ChangeFeedSuccessPage changeFeedSuccessPage))
                {
                    break;
                }

                CosmosArray changes = GetChanges(changeFeedSuccessPage.Content);
                globalChanges.AddRange(changes);

                CosmosElement continuationToken = ((ChangeFeedStateContinuation)enumerator.Current.Result.State).ContinuationToken;

                enumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate(
                    documentContainer,
                    new ChangeFeedRequestOptions(),
                    ChangeFeedStartFrom.ContinuationToken(continuationToken.ToString()),
                    cancellationToken: default).Result;
            }

            return(globalChanges.Count);
        }
        private static async Task <int> DrainWithUntilNotModifiedWithContinuationTokens(
            IDocumentContainer documentContainer,
            CrossPartitionChangeFeedAsyncEnumerator enumerator)
        {
            List <CosmosElement> globalChanges = new List <CosmosElement>();

            while (true)
            {
                if (!await enumerator.MoveNextAsync())
                {
                    throw new InvalidOperationException();
                }

                Assert.IsTrue(enumerator.Current.Succeeded);

                if (!(enumerator.Current.Result.Page is ChangeFeedSuccessPage changeFeedSuccessPage))
                {
                    break;
                }

                CosmosArray changes = GetChanges(changeFeedSuccessPage.Content);
                globalChanges.AddRange(changes);

                enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create(
                    documentContainer,
                    enumerator.Current.Result.State,
                    ChangeFeedPaginationOptions.Default,
                    cancellationToken: default);
            }

            return(globalChanges.Count);
        }
Пример #4
0
        public async Task SomeChangesAsync()
        {
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 1);

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate(
                documentContainer,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Beginning(),
                cancellationToken: default);

            Assert.IsTrue(monadicEnumerator.Succeeded);
            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            // First page should be true and skip the 304 not modified
            Assert.IsTrue(await enumerator.MoveNextAsync());
            Assert.IsTrue(enumerator.Current.Succeeded);
            Assert.IsTrue(enumerator.Current.Result is ChangeFeedSuccessPage);

            // Second page should surface up the 304
            Assert.IsTrue(await enumerator.MoveNextAsync());
            Assert.IsTrue(enumerator.Current.Succeeded);
            Assert.IsTrue(enumerator.Current.Result is ChangeFeedNotModifiedPage);
        }
Пример #5
0
        private static async Task <int> DrainUntilNotModifedAsync(CrossPartitionChangeFeedAsyncEnumerator enumerator)
        {
            int globalCount = 0;

            while (await enumerator.MoveNextAsync())
            {
                Assert.IsTrue(enumerator.Current.Succeeded);
                if (!(enumerator.Current.Result is ChangeFeedSuccessPage changeFeedSuccessPage))
                {
                    break;
                }

                globalCount += GetResponseCount(changeFeedSuccessPage.Content);
            }

            return(globalCount);
        }
        public async Task NoChangesAsync()
        {
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems: 0);
            CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create(
                documentContainer,
                new CrossFeedRangeState<ChangeFeedState>(
                    new FeedRangeState<ChangeFeedState>[]
                    {
                        new FeedRangeState<ChangeFeedState>(FeedRangeEpk.FullRange, ChangeFeedState.Beginning())
                    }),
                ChangeFeedPaginationOptions.Default,
                cancellationToken: default);

            Assert.IsTrue(await enumerator.MoveNextAsync());
            Assert.IsTrue(enumerator.Current.Succeeded);
            Assert.IsTrue(enumerator.Current.Result.Page is ChangeFeedNotModifiedPage);
            Assert.IsNotNull(enumerator.Current.Result.State);
        }
Пример #7
0
        public async Task NoChangesAsync()
        {
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems : 0);

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate(
                documentContainer,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Beginning(),
                cancellationToken: default);

            Assert.IsTrue(monadicEnumerator.Succeeded);
            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            Assert.IsTrue(await enumerator.MoveNextAsync());
            Assert.IsTrue(enumerator.Current.Succeeded);
            Assert.IsTrue(enumerator.Current.Result is ChangeFeedNotModifiedPage);
            Assert.IsNotNull(enumerator.Current.Result.State);
        }
Пример #8
0
        public async Task ChangeFeedAsync()
        {
            int numItems = 100;
            IDocumentContainer documentContainer = await this.CreateDocumentContainerAsync(numItems);

            CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create(
                documentContainer,
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions()
            {
                PageSizeHint = int.MaxValue
            },
                new CrossFeedRangeState <ChangeFeedState>(
                    ChangeFeedCrossFeedRangeState.CreateFromBeginning().FeedRangeStates),
                cancellationToken: default);

            int   numChildren = 0;
            Trace rootTrace;

            using (rootTrace = Trace.GetRootTrace("Cross Partition Change Feed"))
            {
                while (await enumerator.MoveNextAsync(rootTrace))
                {
                    numChildren++;

                    if (enumerator.Current.Result.Page is ChangeFeedNotModifiedPage)
                    {
                        break;
                    }
                }
            }

            string traceString = TraceWriter.TraceToText(rootTrace);

            Console.WriteLine(traceString);

            Assert.AreEqual(numChildren, rootTrace.Children.Count);
        }
Пример #9
0
        public override async Task <ResponseMessage> ReadNextAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = await this.lazyMonadicEnumerator.GetValueAsync(cancellationToken);

            if (monadicEnumerator.Failed)
            {
                Exception       createException = monadicEnumerator.Exception;
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(createException);
                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           diagnostics: new CosmosDiagnosticsContextCore()));
            }

            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            if (!await enumerator.MoveNextAsync())
            {
                throw new InvalidOperationException("ChangeFeed enumerator should always have a next continuation");
            }

            if (enumerator.Current.Failed)
            {
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(enumerator.Current.Exception);
                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           diagnostics: new CosmosDiagnosticsContextCore()));
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> crossFeedRangePage = enumerator.Current.Result;

            Pagination.ChangeFeedPage changeFeedPage = crossFeedRangePage.Page;
            ResponseMessage           responseMessage;

            if (changeFeedPage is Pagination.ChangeFeedSuccessPage changeFeedSuccessPage)
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.OK)
                {
                    Content = changeFeedSuccessPage.Content
                };
            }
            else
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.NotModified);
            }

            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState = crossFeedRangePage.State;
            string continuationToken;

            if (this.changeFeedRequestOptions.EmitOldContinuationToken)
            {
                List <CompositeContinuationToken> compositeContinuationTokens = new List <CompositeContinuationToken>();
                for (int i = 0; i < crossFeedRangeState.Value.Length; i++)
                {
                    FeedRangeState <ChangeFeedState> changeFeedFeedRangeState = crossFeedRangeState.Value.Span[i];
                    string token = changeFeedFeedRangeState.State is ChangeFeedStateContinuation changeFeedStateContinuation ? ((CosmosString)changeFeedStateContinuation.ContinuationToken).Value : null;
                    Documents.Routing.Range <string> range = ((FeedRangeEpk)changeFeedFeedRangeState.FeedRange).Range;
                    CompositeContinuationToken       compositeContinuationToken = new CompositeContinuationToken()
                    {
                        Range = range,
                        Token = token,
                    };

                    compositeContinuationTokens.Add(compositeContinuationToken);
                }

                FeedRangeCompositeContinuation feedRangeCompositeContinuationToken = new FeedRangeCompositeContinuation(
                    await this.documentContainer.GetResourceIdentifierAsync(cancellationToken),
                    FeedRangeEpk.FullRange,
                    compositeContinuationTokens);

                continuationToken = feedRangeCompositeContinuationToken.ToString();
            }
            else
            {
                ChangeFeedCrossFeedRangeState changeFeedCrossFeedRangeState = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
                continuationToken = VersionedAndRidCheckedCompositeToken.ToCosmosElement(
                    new VersionedAndRidCheckedCompositeToken(
                        VersionedAndRidCheckedCompositeToken.Version.V2,
                        changeFeedCrossFeedRangeState.ToCosmosElement(),
                        await this.documentContainer.GetResourceIdentifierAsync(cancellationToken))).ToString();
            }

            responseMessage.Headers.ContinuationToken = continuationToken;
            responseMessage.Headers.RequestCharge     = changeFeedPage.RequestCharge;
            responseMessage.Headers.ActivityId        = changeFeedPage.ActivityId;

            return(responseMessage);
        }
        private async Task <ResponseMessage> ReadNextInternalAsync(ITrace trace, CancellationToken cancellationToken = default)
        {
            if (trace == null)
            {
                throw new ArgumentNullException(nameof(trace));
            }

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = await this.lazyMonadicEnumerator.GetValueAsync(trace, cancellationToken);

            if (monadicEnumerator.Failed)
            {
                Exception createException = monadicEnumerator.Exception;
                if (!ExceptionToCosmosException.TryCreateFromException(
                        createException,
                        trace,
                        out CosmosException cosmosException))
                {
                    // Initialization issue, there are no enumerators to invoke
                    this.hasMoreResults = false;
                    throw createException;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            enumerator.SetCancellationToken(cancellationToken);

            try
            {
                if (!await enumerator.MoveNextAsync(trace))
                {
                    throw new InvalidOperationException("ChangeFeed enumerator should always have a next continuation");
                }
            }
            catch (OperationCanceledException ex) when(!(ex is CosmosOperationCanceledException))
            {
                throw new CosmosOperationCanceledException(ex, trace);
            }

            if (enumerator.Current.Failed)
            {
                if (!ExceptionToCosmosException.TryCreateFromException(
                        enumerator.Current.Exception,
                        trace,
                        out CosmosException cosmosException))
                {
                    throw ExceptionWithStackTraceException.UnWrapMonadExcepion(enumerator.Current.Exception, trace);
                }

                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossFeedRangePage <Pagination.ChangeFeedPage, ChangeFeedState> crossFeedRangePage = enumerator.Current.Result;

            Pagination.ChangeFeedPage changeFeedPage = crossFeedRangePage.Page;
            ResponseMessage           responseMessage;

            if (changeFeedPage is Pagination.ChangeFeedSuccessPage changeFeedSuccessPage)
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.OK)
                {
                    Content = changeFeedSuccessPage.Content
                };
            }
            else
            {
                responseMessage = new ResponseMessage(statusCode: System.Net.HttpStatusCode.NotModified);
            }

            CrossFeedRangeState <ChangeFeedState> crossFeedRangeState           = crossFeedRangePage.State;
            ChangeFeedCrossFeedRangeState         changeFeedCrossFeedRangeState = new ChangeFeedCrossFeedRangeState(crossFeedRangeState.Value);
            string continuationToken = VersionedAndRidCheckedCompositeToken.ToCosmosElement(
                new VersionedAndRidCheckedCompositeToken(
                    VersionedAndRidCheckedCompositeToken.Version.V2,
                    changeFeedCrossFeedRangeState.ToCosmosElement(),
                    await this.documentContainer.GetResourceIdentifierAsync(trace, cancellationToken))).ToString();

            responseMessage.Headers.ContinuationToken = continuationToken;
            responseMessage.Headers.RequestCharge     = changeFeedPage.RequestCharge;
            responseMessage.Headers.ActivityId        = changeFeedPage.ActivityId;
            responseMessage.Trace = trace;

            return(responseMessage);
        }
        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);
        }