Пример #1
0
        public CrossPartitionRangePageAsyncEnumerator(
            IFeedRangeProvider feedRangeProvider,
            CreatePartitionRangePageAsyncEnumerator <TPage, TState> createPartitionRangeEnumerator,
            IComparer <PartitionRangePageAsyncEnumerator <TPage, TState> > comparer,
            int?maxConcurrency,
            CancellationToken cancellationToken,
            CrossPartitionState <TState> state = default)
        {
            if (comparer == null)
            {
                throw new ArgumentNullException(nameof(comparer));
            }

            this.feedRangeProvider = feedRangeProvider ?? throw new ArgumentNullException(nameof(feedRangeProvider));
            this.createPartitionRangeEnumerator = createPartitionRangeEnumerator ?? throw new ArgumentNullException(nameof(createPartitionRangeEnumerator));
            this.cancellationToken = cancellationToken;

            this.lazyEnumerators = new AsyncLazy <PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> > >(async(CancellationToken token) =>
            {
                IReadOnlyList <(PartitionKeyRange, TState)> rangeAndStates;
                if (state != default)
                {
                    rangeAndStates = state.Value;
                }
                else
                {
                    // Fan out to all partitions with default state
                    IEnumerable <PartitionKeyRange> ranges = await feedRangeProvider.GetFeedRangesAsync(token);

                    List <(PartitionKeyRange, TState)> rangesAndStatesBuilder = new List <(PartitionKeyRange, TState)>();
                    foreach (PartitionKeyRange range in ranges)
                    {
                        rangesAndStatesBuilder.Add((range, default));
                    }

                    rangeAndStates = rangesAndStatesBuilder;
                }

                List <BufferedPartitionRangePageAsyncEnumerator <TPage, TState> > bufferedEnumerators = rangeAndStates
                                                                                                        .Select(rangeAndState =>
                {
                    PartitionRangePageAsyncEnumerator <TPage, TState> enumerator = createPartitionRangeEnumerator(rangeAndState.Item1, rangeAndState.Item2);
                    BufferedPartitionRangePageAsyncEnumerator <TPage, TState> bufferedEnumerator = new BufferedPartitionRangePageAsyncEnumerator <TPage, TState>(enumerator, cancellationToken);
                    return(bufferedEnumerator);
                })
                                                                                                        .ToList();

                if (maxConcurrency.HasValue)
                {
                    await ParallelPrefetch.PrefetchInParallelAsync(bufferedEnumerators, maxConcurrency.Value, token);
                }

                PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> > enumerators = new PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> >(
                    bufferedEnumerators,
                    comparer);
                return(enumerators);
            });
        }
 public CrossPartitionRangePageAsyncEnumerable(
     IFeedRangeProvider feedRangeProvider,
     CreatePartitionRangePageAsyncEnumerator <TPage, TState> createPartitionRangeEnumerator,
     IComparer <PartitionRangePageAsyncEnumerator <TPage, TState> > comparer,
     CrossPartitionState <TState> state = default)
 {
     this.feedRangeProvider = feedRangeProvider ?? throw new ArgumentNullException(nameof(comparer));
     this.createPartitionRangeEnumerator = createPartitionRangeEnumerator ?? throw new ArgumentNullException(nameof(createPartitionRangeEnumerator));
     this.comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
     this.state    = state;
 }
        public CrossPartitionRangePageAsyncEnumerator(
            IFeedRangeProvider feedRangeProvider,
            CreatePartitionRangePageAsyncEnumerator <TPage, TState> createPartitionRangeEnumerator,
            IComparer <PartitionRangePageAsyncEnumerator <TPage, TState> > comparer,
            CrossPartitionState <TState> state = default)
        {
            this.feedRangeProvider = feedRangeProvider ?? throw new ArgumentNullException(nameof(feedRangeProvider));
            this.createPartitionRangeEnumerator = createPartitionRangeEnumerator ?? throw new ArgumentNullException(nameof(createPartitionRangeEnumerator));

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

            this.lazyEnumerators = new AsyncLazy <PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> > >(async(CancellationToken token) =>
            {
                IReadOnlyList <(PartitionKeyRange, TState)> rangeAndStates;
                if (state != default)
                {
                    rangeAndStates = state.Value;
                }
                else
                {
                    // Fan out to all partitions with default state
                    IEnumerable <PartitionKeyRange> ranges = await feedRangeProvider.GetFeedRangesAsync(token);

                    List <(PartitionKeyRange, TState)> rangesAndStatesBuilder = new List <(PartitionKeyRange, TState)>();
                    foreach (PartitionKeyRange range in ranges)
                    {
                        rangesAndStatesBuilder.Add((range, default));
                    }

                    rangeAndStates = rangesAndStatesBuilder;
                }

                PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> > enumerators = new PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> >(comparer);
                foreach ((PartitionKeyRange range, TState rangeState) in rangeAndStates)
                {
                    PartitionRangePageAsyncEnumerator <TPage, TState> enumerator = createPartitionRangeEnumerator(range, rangeState);
                    enumerators.Enqueue(enumerator);
                }

                return(enumerators);
            });
        }
Пример #4
0
        public async ValueTask <bool> MoveNextAsync()
        {
            this.cancellationToken.ThrowIfCancellationRequested();

            PriorityQueue <PartitionRangePageAsyncEnumerator <TPage, TState> > enumerators = await this.lazyEnumerators.GetValueAsync(cancellationToken : this.cancellationToken);

            if (enumerators.Count == 0)
            {
                return(false);
            }

            PartitionRangePageAsyncEnumerator <TPage, TState> currentPaginator = enumerators.Dequeue();

            if (!await currentPaginator.MoveNextAsync())
            {
                // Current enumerator is empty,
                // so recursively retry on the next enumerator.
                return(await this.MoveNextAsync());
            }

            if (currentPaginator.Current.Failed)
            {
                // Check if it's a retryable exception.
                Exception exception = currentPaginator.Current.Exception;
                while (exception.InnerException != null)
                {
                    exception = exception.InnerException;
                }

                if (IsSplitException(exception))
                {
                    // Handle split
                    IEnumerable <PartitionKeyRange> childRanges = await this.feedRangeProvider.GetChildRangeAsync(
                        currentPaginator.Range,
                        cancellationToken : this.cancellationToken);

                    foreach (PartitionKeyRange childRange in childRanges)
                    {
                        PartitionRangePageAsyncEnumerator <TPage, TState> childPaginator = this.createPartitionRangeEnumerator(
                            childRange,
                            currentPaginator.State);
                        enumerators.Enqueue(childPaginator);
                    }

                    // Recursively retry
                    return(await this.MoveNextAsync());
                }

                if (IsMergeException(exception))
                {
                    throw new NotImplementedException();
                }

                // Just enqueue the paginator and the user can decide if they want to retry.
                enumerators.Enqueue(currentPaginator);

                this.Current = TryCatch <CrossPartitionPage <TPage, TState> > .FromException(currentPaginator.Current.Exception);

                return(true);
            }

            if (currentPaginator.State != default)
            {
                // Don't enqueue the paginator otherwise it's an infinite loop.
                enumerators.Enqueue(currentPaginator);
            }

            CrossPartitionState <TState> crossPartitionState;

            if (enumerators.Count == 0)
            {
                crossPartitionState = null;
            }
            else
            {
                List <(PartitionKeyRange, TState)> feedRangeAndStates = new List <(PartitionKeyRange, TState)>(enumerators.Count);
                foreach (PartitionRangePageAsyncEnumerator <TPage, TState> enumerator in enumerators)
                {
                    feedRangeAndStates.Add((enumerator.Range, enumerator.State));
                }

                crossPartitionState = new CrossPartitionState <TState>(feedRangeAndStates);
            }

            this.Current = TryCatch <CrossPartitionPage <TPage, TState> > .FromResult(
                new CrossPartitionPage <TPage, TState>(currentPaginator.Current.Result, crossPartitionState));

            return(true);
        }