コード例 #1
0
        public async ValueTask <bool> MoveNextAsync(ITrace trace)
        {
            this.cancellationToken.ThrowIfCancellationRequested();

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

            if (!await this.crossPartitionRangePageAsyncEnumerator.MoveNextAsync(trace))
            {
                this.Current = default;
                return(false);
            }

            TryCatch <CrossFeedRangePage <QueryPage, QueryState> > currentCrossPartitionPage = this.crossPartitionRangePageAsyncEnumerator.Current;

            if (currentCrossPartitionPage.Failed)
            {
                this.Current = TryCatch <QueryPage> .FromException(currentCrossPartitionPage.Exception);

                return(true);
            }

            CrossFeedRangePage <QueryPage, QueryState> crossPartitionPageResult = currentCrossPartitionPage.Result;
            QueryPage backendQueryPage = crossPartitionPageResult.Page;
            CrossFeedRangeState <QueryState> crossPartitionState = crossPartitionPageResult.State;

            QueryState queryState;

            if (crossPartitionState == null)
            {
                queryState = null;
            }
            else
            {
                // left most and any non null continuations
                IOrderedEnumerable <FeedRangeState <QueryState> > feedRangeStates = crossPartitionState
                                                                                    .Value
                                                                                    .ToArray()
                                                                                    .OrderBy(tuple => ((FeedRangeEpk)tuple.FeedRange).Range.Min);

                List <ParallelContinuationToken> activeParallelContinuationTokens = new List <ParallelContinuationToken>();
                {
                    FeedRangeState <QueryState> firstState = feedRangeStates.First();
                    ParallelContinuationToken   firstParallelContinuationToken = new ParallelContinuationToken(
                        token: firstState.State != null ? ((CosmosString)firstState.State.Value).Value : null,
                        range: ((FeedRangeEpk)firstState.FeedRange).Range);

                    activeParallelContinuationTokens.Add(firstParallelContinuationToken);
                }

                foreach (FeedRangeState <QueryState> feedRangeState in feedRangeStates.Skip(1))
                {
                    this.cancellationToken.ThrowIfCancellationRequested();

                    if (feedRangeState.State != null)
                    {
                        ParallelContinuationToken parallelContinuationToken = new ParallelContinuationToken(
                            token: feedRangeState.State != null ? ((CosmosString)feedRangeState.State.Value).Value : null,
                            range: ((FeedRangeEpk)feedRangeState.FeedRange).Range);

                        activeParallelContinuationTokens.Add(parallelContinuationToken);
                    }
                }

                IEnumerable <CosmosElement> cosmosElementContinuationTokens = activeParallelContinuationTokens
                                                                              .Select(token => ParallelContinuationToken.ToCosmosElement(token));
                CosmosArray cosmosElementParallelContinuationTokens = CosmosArray.Create(cosmosElementContinuationTokens);

                queryState = new QueryState(cosmosElementParallelContinuationTokens);
            }

            QueryPage crossPartitionQueryPage = new QueryPage(
                backendQueryPage.Documents,
                backendQueryPage.RequestCharge,
                backendQueryPage.ActivityId,
                backendQueryPage.ResponseLengthInBytes,
                backendQueryPage.CosmosQueryExecutionInfo,
                backendQueryPage.DisallowContinuationTokenMessage,
                queryState);

            this.Current = TryCatch <QueryPage> .FromResult(crossPartitionQueryPage);

            return(true);
        }
        // In order to maintain the continuation token for the user we must drain with a few constraints
        // 1) We fully drain from the left most partition before moving on to the next partition
        // 2) We drain only full pages from the document producer so we aren't left with a partial page
        //  otherwise we would need to add to the continuation token how many items to skip over on that page.
        public async ValueTask <bool> MoveNextAsync()
        {
            this.cancellationToken.ThrowIfCancellationRequested();

            if (!await this.crossPartitionRangePageAsyncEnumerator.MoveNextAsync())
            {
                this.Current = default;
                return(false);
            }

            TryCatch <CrossPartitionPage <QueryPage, QueryState> > currentCrossPartitionPage = this.crossPartitionRangePageAsyncEnumerator.Current;

            if (currentCrossPartitionPage.Failed)
            {
                this.Current = TryCatch <QueryPage> .FromException(currentCrossPartitionPage.Exception);

                return(true);
            }

            CrossPartitionPage <QueryPage, QueryState> crossPartitionPageResult = currentCrossPartitionPage.Result;
            QueryPage backendQueryPage = crossPartitionPageResult.Page;
            CrossPartitionState <QueryState> crossPartitionState = crossPartitionPageResult.State;

            QueryState queryState;

            if (crossPartitionState == null)
            {
                queryState = null;
            }
            else
            {
                // Left most and any non null continuations
                List <(PartitionKeyRange, QueryState)> rangesAndStates = crossPartitionState.Value.OrderBy(tuple => tuple.Item1, PartitionKeyRangeComparer.Singleton).ToList();
                List <ParallelContinuationToken>       activeParallelContinuationTokens = new List <ParallelContinuationToken>();
                for (int i = 0; i < rangesAndStates.Count; i++)
                {
                    this.cancellationToken.ThrowIfCancellationRequested();

                    (PartitionKeyRange range, QueryState state) = rangesAndStates[i];
                    if ((i == 0) || (state != null))
                    {
                        ParallelContinuationToken parallelContinuationToken = new ParallelContinuationToken(
                            token: state != null ? ((CosmosString)state.Value).Value : null,
                            range: range.ToRange());

                        activeParallelContinuationTokens.Add(parallelContinuationToken);
                    }
                }

                IEnumerable <CosmosElement> cosmosElementContinuationTokens = activeParallelContinuationTokens
                                                                              .Select(token => ParallelContinuationToken.ToCosmosElement(token));
                CosmosArray cosmosElementParallelContinuationTokens = CosmosArray.Create(cosmosElementContinuationTokens);

                queryState = new QueryState(cosmosElementParallelContinuationTokens);
            }

            QueryPage crossPartitionQueryPage = new QueryPage(
                backendQueryPage.Documents,
                backendQueryPage.RequestCharge,
                backendQueryPage.ActivityId,
                backendQueryPage.ResponseLengthInBytes,
                backendQueryPage.CosmosQueryExecutionInfo,
                backendQueryPage.DisallowContinuationTokenMessage,
                queryState);

            this.Current = TryCatch <QueryPage> .FromResult(crossPartitionQueryPage);

            return(true);
        }