Exemplo n.º 1
0
        private async Task InitializeAsync(
            string collectionRid,
            List <Range <string> > queryRanges,
            List <PartitionKeyRange> partitionKeyRanges,
            SortOrder[] sortOrders,
            string[] orderByExpressions,
            int initialPageSize,
            string requestContinuation,
            CancellationToken cancellationToken)
        {
            this.InitializationSchedulingMetrics.Start();
            try
            {
                OrderByContinuationToken[] suppliedContinuationTokens = this.ValidateAndExtractContinuationTokens(requestContinuation, sortOrders, orderByExpressions);
                Dictionary <string, OrderByContinuationToken> targetRangeToOrderByContinuationMap = null;
                base.DocumentProducers.Capacity = partitionKeyRanges.Count;

                if (suppliedContinuationTokens == null)
                {
                    await base.InitializeAsync(
                        collectionRid,
                        queryRanges,
                        TaskPriorityFunc,
                        partitionKeyRanges,
                        initialPageSize,
                        new SqlQuerySpec(this.QuerySpec.QueryText.Replace(FormatPlaceHolder, True), this.QuerySpec.Parameters),
                        null,
                        cancellationToken);
                }
                else
                {
                    RangeFilterInitializationInfo[] orderByInfos = this.GetPartitionKeyRangesInitializationInfo(
                        suppliedContinuationTokens,
                        partitionKeyRanges,
                        sortOrders,
                        orderByExpressions,
                        out targetRangeToOrderByContinuationMap);

                    Debug.Assert(targetRangeToOrderByContinuationMap != null, "If targetRangeToOrderByContinuationMap can't be null is valid continuation is supplied");

                    this.currentOrderByItems = suppliedContinuationTokens[0].OrderByItems;

                    // For ascending order-by, left of target partition has filter expression > value,
                    // right of target partition has filter expression >= value,
                    // and target partition takes the previous filter from continuation (or true if no continuation)
                    foreach (RangeFilterInitializationInfo info in orderByInfos)
                    {
                        if (info.StartIndex > info.EndIndex)
                        {
                            continue;
                        }

                        PartialReadOnlyList <PartitionKeyRange> partialRanges =
                            new PartialReadOnlyList <PartitionKeyRange>(partitionKeyRanges, info.StartIndex, info.EndIndex - info.StartIndex + 1);

                        Task initTask = base.InitializeAsync(
                            collectionRid,
                            queryRanges,
                            TaskPriorityFunc,
                            partialRanges,
                            initialPageSize,
                            new SqlQuerySpec(
                                this.QuerySpec.QueryText.Replace(FormatPlaceHolder, info.Filter),
                                this.QuerySpec.Parameters),
                            targetRangeToOrderByContinuationMap.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.CompositeToken.Token),
                            cancellationToken);

                        foreach (PartitionKeyRange range in partialRanges)
                        {
                            this.filters[range.Id] = info.Filter;
                        }

                        await initTask;
                    }
                }

                // The Foreach loop below is an optimization for the following While loop. The While loop is made single-threaded as the base.DocumentProducers object can change during runtime due to split. Even though the While loop is single threaded, the Foreach loop below makes the producers fetch doucments concurrently. If any of the producers fails to produce due to split (i.e., encounters PartitionKeyRangeGoneException), then the while loop below will take out the failed document producers and replace it approprite ones and then call TryScheduleFetch() on them.
                foreach (var producer in base.DocumentProducers)
                {
                    producer.TryScheduleFetch();
                }

                // Fetch one item from each of the producers to initialize the priority-queue. "TryMoveNextProducerAsync()" has
                // a side-effect that, if Split is encountered while trying to move, related parent producer will be taken out and child
                // producers will be added to "base.DocumentProducers".

                for (int index = 0; index < base.DocumentProducers.Count; ++index)
                {
                    DocumentProducer <OrderByQueryResult> producer = base.DocumentProducers[index];

                    if (await this.TryMoveNextProducerAsync(
                            producer,
                            targetRangeToOrderByContinuationMap,
                            cancellationToken: cancellationToken))
                    {
                        producer = base.DocumentProducers[index];

                        OrderByContinuationToken continuationToken =
                            (targetRangeToOrderByContinuationMap != null && targetRangeToOrderByContinuationMap.ContainsKey(producer.TargetRange.Id)) ?
                            targetRangeToOrderByContinuationMap[producer.TargetRange.Id] : null;

                        if (continuationToken != null)
                        {
                            await this.FilterAsync(producer, sortOrders, continuationToken, cancellationToken);
                        }

                        this.documentProducerConsumerQueue.Enqueue(producer);
                    }
                }
            }
            finally
            {
                this.InitializationSchedulingMetrics.Stop();
                DefaultTrace.TraceInformation(string.Format(
                                                  CultureInfo.InvariantCulture,
                                                  "{0}, CorrelatedActivityId: {1} | OrderBy~Context.InitializeAsync",
                                                  DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture),
                                                  this.CorrelatedActivityId));
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initializes this execution context.
        /// </summary>
        /// <param name="requestContinuation">The continuation token to resume from (or null if none).</param>
        /// <param name="collectionRid">The collection rid.</param>
        /// <param name="partitionKeyRanges">The partition key ranges to drain from.</param>
        /// <param name="initialPageSize">The initial page size.</param>
        /// <param name="sortOrders">The sort orders.</param>
        /// <param name="orderByExpressions">The order by expressions.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on.</returns>
        private async Task InitializeAsync(
            string requestContinuation,
            string collectionRid,
            List <PartitionKeyRange> partitionKeyRanges,
            int initialPageSize,
            SortOrder[] sortOrders,
            string[] orderByExpressions,
            CancellationToken cancellationToken)
        {
            try
            {
                if (requestContinuation == null)
                {
                    await base.InitializeAsync(
                        collectionRid,
                        partitionKeyRanges,
                        initialPageSize,
                        token : cancellationToken,
                        querySpecForInit : new SqlQuerySpec(this.QuerySpec.QueryText.Replace(FormatPlaceHolder, True), this.QuerySpec.Parameters),
                        targetRangeToContinuationMap : null,
                        deferFirstPage : false,
                        filter : null,
                        filterCallback : null);
                }
                else
                {
                    OrderByContinuationToken[] suppliedContinuationTokens = this.ValidateAndExtractContinuationToken(
                        requestContinuation,
                        sortOrders,
                        orderByExpressions);
                    Dictionary <string, OrderByContinuationToken> targetRangeToOrderByContinuationMap = null;

                    RangeFilterInitializationInfo[] orderByInfos = this.GetPartitionKeyRangesInitializationInfo(
                        suppliedContinuationTokens,
                        partitionKeyRanges,
                        sortOrders,
                        orderByExpressions,
                        out targetRangeToOrderByContinuationMap);

                    Debug.Assert(targetRangeToOrderByContinuationMap != null, "If targetRangeToOrderByContinuationMap can't be null is valid continuation is supplied");

                    // For ascending order-by, left of target partition has filter expression > value,
                    // right of target partition has filter expression >= value,
                    // and target partition takes the previous filter from continuation (or true if no continuation)
                    foreach (RangeFilterInitializationInfo info in orderByInfos)
                    {
                        if (info.StartIndex > info.EndIndex)
                        {
                            continue;
                        }

                        PartialReadOnlyList <PartitionKeyRange> partialRanges =
                            new PartialReadOnlyList <PartitionKeyRange>(partitionKeyRanges, info.StartIndex, info.EndIndex - info.StartIndex + 1);

                        await base.InitializeAsync(
                            collectionRid,
                            partialRanges,
                            initialPageSize,
                            new SqlQuerySpec(
                                this.QuerySpec.QueryText.Replace(FormatPlaceHolder, info.Filter),
                                this.QuerySpec.Parameters),
                            targetRangeToOrderByContinuationMap.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.CompositeContinuationToken.Token),
                            false,
                            info.Filter,
                            async (documentProducerTree) =>
                        {
                            OrderByContinuationToken continuationToken;
                            if (targetRangeToOrderByContinuationMap.TryGetValue(documentProducerTree.Root.PartitionKeyRange.Id, out continuationToken))
                            {
                                await this.FilterAsync(
                                    documentProducerTree,
                                    sortOrders,
                                    continuationToken,
                                    cancellationToken);
                            }
                        },
                            cancellationToken);
                    }
                }
            }
            finally
            {
                this.TraceInformation("OrderBy~Context.InitializeAsync");
            }
        }
        private async Task <TryCatch <bool> > TryInitializeAsync(
            SqlQuerySpec sqlQuerySpec,
            string requestContinuation,
            string collectionRid,
            List <PartitionKeyRange> partitionKeyRanges,
            int initialPageSize,
            SortOrder[] sortOrders,
            string[] orderByExpressions,
            CancellationToken cancellationToken)
        {
            if (sqlQuerySpec == null)
            {
                throw new ArgumentNullException(nameof(sqlQuerySpec));
            }

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

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

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

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

            cancellationToken.ThrowIfCancellationRequested();

            if (requestContinuation == null)
            {
                SqlQuerySpec sqlQuerySpecForInit = new SqlQuerySpec(
                    sqlQuerySpec.QueryText.Replace(oldValue: FormatPlaceHolder, newValue: True),
                    sqlQuerySpec.Parameters);

                TryCatch <bool> tryInitialize = await base.TryInitializeAsync(
                    collectionRid,
                    partitionKeyRanges,
                    initialPageSize,
                    sqlQuerySpecForInit,
                    cancellationToken : cancellationToken,
                    targetRangeToContinuationMap : null,
                    deferFirstPage : false,
                    filter : null,
                    tryFilterAsync : null);

                if (!tryInitialize.Succeeded)
                {
                    return(tryInitialize);
                }
            }
            else
            {
                TryCatch <OrderByContinuationToken[]> tryExtractContinuationTokens = CosmosOrderByItemQueryExecutionContext.TryExtractContinuationTokens(
                    requestContinuation,
                    sortOrders,
                    orderByExpressions);
                if (!tryExtractContinuationTokens.Succeeded)
                {
                    return(TryCatch <bool> .FromException(tryExtractContinuationTokens.Exception));
                }

                TryCatch <OrderByInitInfo> tryGetOrderByInitInfo = CosmosOrderByItemQueryExecutionContext.TryGetOrderByPartitionKeyRangesInitializationInfo(
                    tryExtractContinuationTokens.Result,
                    partitionKeyRanges,
                    sortOrders,
                    orderByExpressions);
                if (!tryGetOrderByInitInfo.Succeeded)
                {
                    return(TryCatch <bool> .FromException(tryGetOrderByInitInfo.Exception));
                }

                OrderByInitInfo initiaizationInfo            = tryGetOrderByInitInfo.Result;
                RangeFilterInitializationInfo[] orderByInfos = initiaizationInfo.Filters;
                IReadOnlyDictionary <string, OrderByContinuationToken> targetRangeToOrderByContinuationMap = initiaizationInfo.ContinuationTokens;
                Debug.Assert(
                    targetRangeToOrderByContinuationMap != null,
                    "If targetRangeToOrderByContinuationMap can't be null is valid continuation is supplied");

                // For ascending order-by, left of target partition has filter expression > value,
                // right of target partition has filter expression >= value,
                // and target partition takes the previous filter from continuation (or true if no continuation)
                foreach (RangeFilterInitializationInfo info in orderByInfos)
                {
                    if (info.StartIndex > info.EndIndex)
                    {
                        continue;
                    }

                    PartialReadOnlyList <PartitionKeyRange> partialRanges =
                        new PartialReadOnlyList <PartitionKeyRange>(
                            partitionKeyRanges,
                            info.StartIndex,
                            info.EndIndex - info.StartIndex + 1);

                    SqlQuerySpec sqlQuerySpecForInit = new SqlQuerySpec(
                        sqlQuerySpec.QueryText.Replace(FormatPlaceHolder, info.Filter),
                        sqlQuerySpec.Parameters);

                    await base.TryInitializeAsync(
                        collectionRid,
                        partialRanges,
                        initialPageSize,
                        sqlQuerySpecForInit,
                        targetRangeToOrderByContinuationMap.ToDictionary(
                            kvp => kvp.Key,
                            kvp => kvp.Value.CompositeContinuationToken.Token),
                        false,
                        info.Filter,
                        async (itemProducerTree) =>
                    {
                        if (targetRangeToOrderByContinuationMap.TryGetValue(
                                itemProducerTree.Root.PartitionKeyRange.Id,
                                out OrderByContinuationToken continuationToken))
                        {
                            TryCatch <bool> tryFilter = await this.TryFilterAsync(
                                itemProducerTree,
                                sortOrders,
                                continuationToken,
                                cancellationToken);

                            if (!tryFilter.Succeeded)
                            {
                                return(tryFilter);
                            }
                        }

                        return(TryCatch <bool> .FromResult(true));
                    },
                        cancellationToken);
                }
            }

            return(TryCatch <bool> .FromResult(true));
        }