public static async Task <TryCatch <CosmosOrderByItemQueryExecutionContext> > TryCreateAsync(
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken cancellationToken)
        {
            Debug.Assert(
                initParams.PartitionedQueryExecutionInfo.QueryInfo.HasOrderBy,
                "OrderBy~Context must have order by query info.");

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

            cancellationToken.ThrowIfCancellationRequested();

            CosmosOrderByItemQueryExecutionContext context = new CosmosOrderByItemQueryExecutionContext(
                initPararms: queryContext,
                maxConcurrency: initParams.MaxConcurrency,
                maxItemCount: initParams.MaxItemCount,
                maxBufferedItemCount: initParams.MaxBufferedItemCount,
                consumeComparer: new OrderByConsumeComparer(initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderBy));

            return((await context.TryInitializeAsync(
                        sqlQuerySpec: initParams.SqlQuerySpec,
                        requestContinuation: requestContinuationToken,
                        collectionRid: initParams.CollectionRid,
                        partitionKeyRanges: initParams.PartitionKeyRanges,
                        initialPageSize: initParams.InitialPageSize,
                        sortOrders: initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderBy,
                        orderByExpressions: initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderByExpressions,
                        cancellationToken: cancellationToken))
                   .Try <CosmosOrderByItemQueryExecutionContext>((ignore) => context));
        }
예제 #2
0
 /// <summary>
 /// Callback to create a child document producer tree based on the partition key range.
 /// </summary>
 /// <param name="queryContext">request context</param>
 /// <param name="querySpecForInit">query spec for initialization</param>
 /// <param name="produceAsyncCompleteCallback">Callback to invoke once a fetch finishes.</param>
 /// <param name="itemProducerTreeComparer">Comparer to determine, which tree to produce from.</param>
 /// <param name="equalityComparer">Comparer to see if we need to return the continuation token for a partition.</param>
 /// <param name="deferFirstPage">Whether or not to defer fetching the first page.</param>
 /// <param name="collectionRid">The collection to drain from.</param>
 /// <param name="initialPageSize">The initial page size.</param>
 /// <returns>A function that given a partition key range and continuation token will create a document producer.</returns>
 private static Func <Documents.PartitionKeyRange, string, ItemProducerTree> CreateItemProducerTreeCallback(
     CosmosQueryContext queryContext,
     SqlQuerySpec querySpecForInit,
     ProduceAsyncCompleteDelegate produceAsyncCompleteCallback,
     IComparer <ItemProducerTree> itemProducerTreeComparer,
     IEqualityComparer <CosmosElement> equalityComparer,
     bool deferFirstPage,
     string collectionRid,
     long initialPageSize = 50)
 {
     return((partitionKeyRange, continuationToken) =>
     {
         return new ItemProducerTree(
             queryContext,
             querySpecForInit,
             partitionKeyRange,
             produceAsyncCompleteCallback,
             itemProducerTreeComparer,
             equalityComparer,
             deferFirstPage,
             collectionRid,
             initialPageSize,
             continuationToken);
     });
 }
 /// <summary>
 /// Callback to create a child document producer tree based on the partition key range.
 /// </summary>
 /// <param name="queryContext">request context</param>
 /// <param name="querySpecForInit">query spec for initialization</param>
 /// <param name="createRetryPolicyFunc">Callback to create a retry policy.</param>
 /// <param name="produceAsyncCompleteCallback">Callback to invoke once a fetch finishes.</param>
 /// <param name="itemProducerTreeComparer">Comparer to determine, which tree to produce from.</param>
 /// <param name="equalityComparer">Comparer to see if we need to return the continuation token for a partition.</param>
 /// <param name="deferFirstPage">Whether or not to defer fetching the first page.</param>
 /// <param name="collectionRid">The collection to drain from.</param>
 /// <param name="initialPageSize">The initial page size.</param>
 /// <returns>A function that given a partition key range and continuation token will create a document producer.</returns>
 private static Func <PartitionKeyRange, string, ItemProducerTree> CreateItemProducerTreeCallback(
     CosmosQueryContext queryContext,
     SqlQuerySpec querySpecForInit,
     Func <IDocumentClientRetryPolicy> createRetryPolicyFunc,
     Action <ItemProducerTree, int, double, QueryMetrics, long, CancellationToken> produceAsyncCompleteCallback,
     IComparer <ItemProducerTree> itemProducerTreeComparer,
     IEqualityComparer <CosmosElement> equalityComparer,
     bool deferFirstPage,
     string collectionRid,
     long initialPageSize = 50)
 {
     return((partitionKeyRange, continuationToken) =>
     {
         return new ItemProducerTree(
             queryContext,
             querySpecForInit,
             partitionKeyRange,
             createRetryPolicyFunc,
             produceAsyncCompleteCallback,
             itemProducerTreeComparer,
             equalityComparer,
             deferFirstPage,
             collectionRid,
             initialPageSize,
             continuationToken);
     });
 }
        public override async Task <ResponseMessage> ReadNextAsync(CancellationToken cancellationToken = default)
        {
            CosmosDiagnosticsContext diagnostics = new CosmosDiagnosticsContext();

            using (diagnostics.CreateScope("QueryReadNextAsync"))
            {
                // This catches exception thrown by the pipeline and converts it to QueryResponse
                QueryResponseCore responseCore = await this.cosmosQueryExecutionContext.ExecuteNextAsync(cancellationToken);

                CosmosQueryContext cosmosQueryContext = this.cosmosQueryContext;

                foreach (QueryPageDiagnostics queryPage in responseCore.Diagnostics)
                {
                    diagnostics.Summary.Append(queryPage.DiagnosticsContext.Summary);
                    diagnostics.AddDiagnosticsInternal(queryPage);
                }

                QueryResponse queryResponse;
                if (responseCore.IsSuccess)
                {
                    queryResponse = QueryResponse.CreateSuccess(
                        result: responseCore.CosmosElements,
                        count: responseCore.CosmosElements.Count,
                        responseLengthBytes: responseCore.ResponseLengthBytes,
                        diagnostics: diagnostics,
                        serializationOptions: this.cosmosSerializationFormatOptions,
                        responseHeaders: new CosmosQueryResponseMessageHeaders(
                            responseCore.ContinuationToken,
                            responseCore.DisallowContinuationTokenMessage,
                            cosmosQueryContext.ResourceTypeEnum,
                            cosmosQueryContext.ContainerResourceId)
                    {
                        RequestCharge = responseCore.RequestCharge,
                        ActivityId    = responseCore.ActivityId,
                        SubStatusCode = responseCore.SubStatusCode ?? Documents.SubStatusCodes.Unknown
                    });
                }
                else
                {
                    queryResponse = QueryResponse.CreateFailure(
                        statusCode: responseCore.StatusCode,
                        error: null,
                        errorMessage: responseCore.ErrorMessage,
                        requestMessage: null,
                        diagnostics: diagnostics,
                        responseHeaders: new CosmosQueryResponseMessageHeaders(
                            responseCore.ContinuationToken,
                            responseCore.DisallowContinuationTokenMessage,
                            cosmosQueryContext.ResourceTypeEnum,
                            cosmosQueryContext.ContainerResourceId)
                    {
                        RequestCharge = responseCore.RequestCharge,
                        ActivityId    = responseCore.ActivityId,
                        SubStatusCode = responseCore.SubStatusCode ?? Documents.SubStatusCodes.Unknown
                    });
                }

                return(queryResponse);
            }
        }
예제 #5
0
        /// <summary>
        /// Initializes a new instance of the CosmosCrossPartitionQueryExecutionContext class.
        /// </summary>
        /// <param name="initParams">Constructor parameters for the base class.</param>
        /// <param name="moveNextComparer">Comparer used to figure out that document producer tree to serve documents from next.</param>
        /// <param name="fetchPrioirtyFunction">The priority function to determine which partition to fetch documents from next.</param>
        /// <param name="equalityComparer">Used to determine whether we need to return the continuation token for a partition.</param>
        protected CosmosCrossPartitionQueryExecutionContext(
            CosmosQueryContext initParams,
            IComparer <ItemProducerTree> moveNextComparer,
            Func <ItemProducerTree, int> fetchPrioirtyFunction,
            IEqualityComparer <CosmosElement> equalityComparer)
        {
            if (moveNextComparer == null)
            {
                throw new ArgumentNullException(nameof(moveNextComparer));
            }

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

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

            this.queryContext            = initParams;
            this.queryRequestOptions     = initParams.QueryRequestOptions;
            this.itemProducerForest      = new PriorityQueue <ItemProducerTree>(moveNextComparer, isSynchronized: true);
            this.fetchPrioirtyFunction   = fetchPrioirtyFunction;
            this.comparableTaskScheduler = new ComparableTaskScheduler(initParams.QueryRequestOptions.MaxConcurrency.GetValueOrDefault(0));
            this.equalityComparer        = equalityComparer;
            this.requestChargeTracker    = new RequestChargeTracker();
            this.partitionedQueryMetrics = new ConcurrentBag <Tuple <string, QueryMetrics> >();
            this.actualMaxPageSize       = this.queryRequestOptions.MaxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalMaxItemCount);

            if (this.actualMaxPageSize < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be less than 0");
            }

            if (this.actualMaxPageSize > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be greater than int.MaxValue");
            }

            if (this.queryRequestOptions.MaxBufferedItemCount.HasValue)
            {
                this.actualMaxBufferedItemCount = this.queryRequestOptions.MaxBufferedItemCount.Value;
            }
            else
            {
                this.actualMaxBufferedItemCount = ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize;
            }

            if (this.actualMaxBufferedItemCount < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be less than 0");
            }

            if (this.actualMaxBufferedItemCount > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be greater than int.MaxValue");
            }
        }
예제 #6
0
        public CosmosQueryExecutionContextFactory(
            CosmosQueryContext cosmosQueryContext,
            InputParameters inputParameters)
        {
            if (cosmosQueryContext == null)
            {
                throw new ArgumentNullException(nameof(cosmosQueryContext));
            }

            this.CosmosQueryContext = cosmosQueryContext;
            this.inputParameters    = inputParameters;

            // Swapping out negative values in feedOptions for int.MaxValue
            if (this.inputParameters.MaxBufferedItemCount.HasValue && this.inputParameters.MaxBufferedItemCount < 0)
            {
                this.inputParameters.MaxBufferedItemCount = int.MaxValue;
            }

            if (this.inputParameters.MaxConcurrency.HasValue && this.inputParameters.MaxConcurrency < 0)
            {
                this.inputParameters.MaxConcurrency = int.MaxValue;
            }

            if (this.inputParameters.MaxItemCount.HasValue && this.inputParameters.MaxItemCount < 0)
            {
                this.inputParameters.MaxItemCount = int.MaxValue;
            }
        }
예제 #7
0
        public static async Task <TryCatch <CosmosParallelItemQueryExecutionContext> > TryCreateAsync(
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken cancellationToken)
        {
            Debug.Assert(
                !initParams.PartitionedQueryExecutionInfo.QueryInfo.HasOrderBy,
                "Parallel~Context must not have order by query info.");

            cancellationToken.ThrowIfCancellationRequested();

            CosmosParallelItemQueryExecutionContext context = new CosmosParallelItemQueryExecutionContext(
                queryContext: queryContext,
                maxConcurrency: initParams.MaxConcurrency,
                maxItemCount: initParams.MaxItemCount,
                maxBufferedItemCount: initParams.MaxBufferedItemCount);

            return(await context.TryInitializeAsync(
                       sqlQuerySpec : initParams.SqlQuerySpec,
                       collectionRid : initParams.CollectionRid,
                       partitionKeyRanges : initParams.PartitionKeyRanges,
                       initialPageSize : initParams.InitialPageSize,
                       requestContinuation : requestContinuationToken,
                       cancellationToken : cancellationToken));
        }
        /// <summary>
        /// Creates an CosmosOrderByItemQueryExecutionContext
        /// </summary>
        /// <param name="constructorParams">The parameters for the base class constructor.</param>
        /// <param name="initParams">The parameters to initialize the base class.</param>
        /// <param name="token">The cancellation token.</param>
        /// <returns>A task to await on, which in turn creates an CosmosOrderByItemQueryExecutionContext.</returns>
        public static async Task <CosmosOrderByItemQueryExecutionContext> CreateAsync(
            CosmosQueryContext constructorParams,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            CancellationToken token)
        {
            Debug.Assert(
                initParams.PartitionedQueryExecutionInfo.QueryInfo.HasOrderBy,
                "OrderBy~Context must have order by query info.");

            CosmosOrderByItemQueryExecutionContext context = new CosmosOrderByItemQueryExecutionContext(
                constructorParams,
                new OrderByConsumeComparer(initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderBy));

            await context.InitializeAsync(
                constructorParams.SqlQuerySpec,
                initParams.RequestContinuation,
                initParams.CollectionRid,
                initParams.PartitionKeyRanges,
                initParams.InitialPageSize,
                initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderBy,
                initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderByExpressions,
                token);

            return(context);
        }
예제 #9
0
        /// <summary>
        /// Creates an CosmosOrderByItemQueryExecutionContext
        /// </summary>
        /// <param name="queryContext">The parameters for the base class constructor.</param>
        /// <param name="initParams">The parameters to initialize the base class.</param>
        /// <param name="requestContinuationToken">The request continuation.</param>
        /// <param name="token">The cancellation token.</param>
        /// <returns>A task to await on, which in turn creates an CosmosOrderByItemQueryExecutionContext.</returns>
        public static async Task <CosmosOrderByItemQueryExecutionContext> CreateAsync(
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken token)
        {
            Debug.Assert(
                initParams.PartitionedQueryExecutionInfo.QueryInfo.HasOrderBy,
                "OrderBy~Context must have order by query info.");

            CosmosOrderByItemQueryExecutionContext context = new CosmosOrderByItemQueryExecutionContext(
                initPararms: queryContext,
                maxConcurrency: initParams.MaxConcurrency,
                maxItemCount: initParams.MaxItemCount,
                maxBufferedItemCount: initParams.MaxBufferedItemCount,
                consumeComparer: new OrderByConsumeComparer(initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderBy));

            await context.InitializeAsync(
                sqlQuerySpec : initParams.SqlQuerySpec,
                requestContinuation : requestContinuationToken,
                collectionRid : initParams.CollectionRid,
                partitionKeyRanges : initParams.PartitionKeyRanges,
                initialPageSize : initParams.InitialPageSize,
                sortOrders : initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderBy,
                orderByExpressions : initParams.PartitionedQueryExecutionInfo.QueryInfo.OrderByExpressions,
                cancellationToken : token);

            return(context);
        }
        /// <summary>
        /// Creates a CosmosPipelinedItemQueryExecutionContext.
        /// </summary>
        /// <param name="queryContext">The parameters for constructing the base class.</param>
        /// <param name="initParams">The initial parameters</param>
        /// <param name="requestContinuationToken">The request continuation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on, which in turn returns a CosmosPipelinedItemQueryExecutionContext.</returns>
        public static async Task <CosmosQueryExecutionContext> CreateAsync(
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken cancellationToken)
        {
            DefaultTrace.TraceInformation(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}, CorrelatedActivityId: {1} | Pipelined~Context.CreateAsync",
                    DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture),
                    queryContext.CorrelatedActivityId));

            QueryInfo queryInfo = initParams.PartitionedQueryExecutionInfo.QueryInfo;

            int actualPageSize  = initParams.InitialPageSize;
            int initialPageSize = initParams.InitialPageSize;

            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams parameters = initParams;
            if (queryInfo.HasGroupBy)
            {
                initialPageSize = int.MaxValue;
                initParams      = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    sqlQuerySpec: initParams.SqlQuerySpec,
                    collectionRid: initParams.CollectionRid,
                    partitionedQueryExecutionInfo: initParams.PartitionedQueryExecutionInfo,
                    partitionKeyRanges: initParams.PartitionKeyRanges,
                    initialPageSize: initialPageSize,
                    maxConcurrency: initParams.MaxConcurrency,
                    maxItemCount: int.MaxValue,
                    maxBufferedItemCount: initParams.MaxBufferedItemCount);
            }

            Func <string, Task <IDocumentQueryExecutionComponent> > createOrderByComponentFunc = async(continuationToken) =>
            {
                return(await CosmosOrderByItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            Func <string, Task <IDocumentQueryExecutionComponent> > createParallelComponentFunc = async(continuationToken) =>
            {
                return(await CosmosParallelItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            return((CosmosQueryExecutionContext)await PipelinedDocumentQueryExecutionContext.CreateHelperAsync(
                       queryContext.QueryClient,
                       initParams.PartitionedQueryExecutionInfo.QueryInfo,
                       initialPageSize,
                       requestContinuationToken,
                       createOrderByComponentFunc,
                       createParallelComponentFunc));
        }
예제 #11
0
        /// <summary>
        /// Initializes a new instance of the ItemProducer class.
        /// </summary>
        /// <param name="queryContext">request context</param>
        /// <param name="querySpecForInit">query spec for initialization</param>
        /// <param name="partitionKeyRange">The partition key range.</param>
        /// <param name="createRetryPolicyFunc">The callback to create the retry policy.</param>
        /// <param name="produceAsyncCompleteCallback">The callback to call once you are done fetching.</param>
        /// <param name="equalityComparer">The comparer to use to determine whether the producer has seen a new document.</param>
        /// <param name="initialPageSize">The initial page size.</param>
        /// <param name="initialContinuationToken">The initial continuation token.</param>
        public ItemProducer(
            CosmosQueryContext queryContext,
            SqlQuerySpec querySpecForInit,
            PartitionKeyRange partitionKeyRange,
            Func <IDocumentClientRetryPolicy> createRetryPolicyFunc,
            ProduceAsyncCompleteDelegate produceAsyncCompleteCallback,
            IEqualityComparer <CosmosElement> equalityComparer,
            long initialPageSize            = 50,
            string initialContinuationToken = null)
        {
            this.bufferedPages = new AsyncCollection <TryMonad <FeedResponse <CosmosElement> > >();

            // We use a binary semaphore to get the behavior of a mutex,
            // since fetching documents from the backend using a continuation token is a critical section.
            this.fetchSemaphore = new SemaphoreSlim(1, 1);
            if (partitionKeyRange == null)
            {
                throw new ArgumentNullException(nameof(partitionKeyRange));
            }

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

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

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

            this.queryContext                 = queryContext;
            this.querySpecForInit             = querySpecForInit;
            this.PartitionKeyRange            = partitionKeyRange;
            this.createRetryPolicyFunc        = createRetryPolicyFunc;
            this.produceAsyncCompleteCallback = produceAsyncCompleteCallback;
            this.equalityComparer             = equalityComparer;
            this.pageSize = initialPageSize;
            this.currentContinuationToken  = initialContinuationToken;
            this.BackendContinuationToken  = initialContinuationToken;
            this.PreviousContinuationToken = initialContinuationToken;
            if (!string.IsNullOrEmpty(initialContinuationToken))
            {
                this.hasStartedFetching = true;
                this.IsActive           = true;
            }

            this.fetchSchedulingMetrics = new SchedulingStopwatch();
            this.fetchSchedulingMetrics.Ready();
            this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator();

            this.HasMoreResults = true;
        }
예제 #12
0
 /// <summary>
 /// Initializes a new instance of the CosmosParallelItemQueryExecutionContext class.
 /// </summary>
 /// <param name="constructorParams">The parameters for constructing the base class.</param>
 private CosmosParallelItemQueryExecutionContext(
     CosmosQueryContext constructorParams)
     : base(
         constructorParams,
         CosmosParallelItemQueryExecutionContext.MoveNextComparer,
         CosmosParallelItemQueryExecutionContext.FetchPriorityFunction,
         CosmosParallelItemQueryExecutionContext.EqualityComparer)
 {
 }
예제 #13
0
 private QueryIterator(
     CosmosQueryContext cosmosQueryContext,
     CosmosQueryExecutionContext cosmosQueryExecutionContext,
     CosmosSerializationFormatOptions cosmosSerializationFormatOptions)
 {
     this.cosmosQueryContext               = cosmosQueryContext ?? throw new ArgumentNullException(nameof(cosmosQueryContext));
     this.cosmosQueryExecutionContext      = cosmosQueryExecutionContext ?? throw new ArgumentNullException(nameof(cosmosQueryExecutionContext));
     this.cosmosSerializationFormatOptions = cosmosSerializationFormatOptions;
 }
 /// <summary>
 /// Initializes a new instance of the CosmosOrderByItemQueryExecutionContext class.
 /// </summary>
 /// <param name="initPararms">The params used to construct the base class.</param>
 /// For cross partition order by queries a query like "SELECT c.id, c.field_0 ORDER BY r.field_7 gets rewritten as:
 /// <![CDATA[
 /// SELECT r._rid, [{"item": r.field_7}] AS orderByItems, {"id": r.id, "field_0": r.field_0} AS payload
 /// FROM r
 /// WHERE({ document db - formattable order by query - filter})
 /// ORDER BY r.field_7]]>
 /// This is needed because we need to add additional filters to the query when we resume from a continuation,
 /// and it lets us easily parse out the _rid orderByItems, and payload without parsing the entire document (and having to remember the order by field).
 /// <param name="consumeComparer">Comparer used to internally compare documents from different sorted partitions.</param>
 private CosmosOrderByItemQueryExecutionContext(
     CosmosQueryContext initPararms,
     OrderByConsumeComparer consumeComparer)
     : base(
         initPararms,
         consumeComparer,
         CosmosOrderByItemQueryExecutionContext.FetchPriorityFunction,
         new OrderByEqualityComparer(consumeComparer))
 {
 }
        /// <summary>
        /// Creates a CosmosPipelinedItemQueryExecutionContext.
        /// </summary>
        /// <param name="executionEnvironment">The environment to execute on.</param>
        /// <param name="queryContext">The parameters for constructing the base class.</param>
        /// <param name="initParams">The initial parameters</param>
        /// <param name="requestContinuationToken">The request continuation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on, which in turn returns a CosmosPipelinedItemQueryExecutionContext.</returns>
        public static async Task <CosmosQueryExecutionContext> CreateAsync(
            ExecutionEnvironment executionEnvironment,
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            QueryInfo queryInfo = initParams.PartitionedQueryExecutionInfo.QueryInfo;

            int initialPageSize = initParams.InitialPageSize;

            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams parameters = initParams;
            if (queryInfo.HasGroupBy)
            {
                // The query will block until all groupings are gathered so we might as well speed up the process.
                initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    sqlQuerySpec: initParams.SqlQuerySpec,
                    collectionRid: initParams.CollectionRid,
                    partitionedQueryExecutionInfo: initParams.PartitionedQueryExecutionInfo,
                    partitionKeyRanges: initParams.PartitionKeyRanges,
                    initialPageSize: int.MaxValue,
                    maxConcurrency: initParams.MaxConcurrency,
                    maxItemCount: int.MaxValue,
                    maxBufferedItemCount: initParams.MaxBufferedItemCount);
            }

            Func <string, Task <IDocumentQueryExecutionComponent> > createOrderByComponentFunc = async(continuationToken) =>
            {
                return(await CosmosOrderByItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            Func <string, Task <IDocumentQueryExecutionComponent> > createParallelComponentFunc = async(continuationToken) =>
            {
                return(await CosmosParallelItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            return((CosmosQueryExecutionContext)await PipelinedDocumentQueryExecutionContext.CreateHelperAsync(
                       executionEnvironment,
                       queryContext.QueryClient,
                       initParams.PartitionedQueryExecutionInfo.QueryInfo,
                       initialPageSize,
                       requestContinuationToken,
                       createOrderByComponentFunc,
                       createParallelComponentFunc));
        }
        /// <summary>
        /// Creates a CosmosPipelinedItemQueryExecutionContext.
        /// </summary>
        /// <param name="constructorParams">The parameters for constructing the base class.</param>
        /// <param name="collectionRid">The collection rid.</param>
        /// <param name="partitionedQueryExecutionInfo">The partitioned query execution info.</param>
        /// <param name="partitionKeyRanges">The partition key ranges.</param>
        /// <param name="initialPageSize">The initial page size.</param>
        /// <param name="requestContinuation">The request continuation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on, which in turn returns a CosmosPipelinedItemQueryExecutionContext.</returns>
        public static async Task <CosmosQueryExecutionContext> CreateAsync(
            CosmosQueryContext constructorParams,
            string collectionRid,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            List <PartitionKeyRange> partitionKeyRanges,
            int initialPageSize,
            string requestContinuation,
            CancellationToken cancellationToken)
        {
            DefaultTrace.TraceInformation(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}, CorrelatedActivityId: {1} | Pipelined~Context.CreateAsync",
                    DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture),
                    constructorParams.CorrelatedActivityId));

            Func <string, Task <IDocumentQueryExecutionComponent> > createOrderByComponentFunc = async(continuationToken) =>
            {
                CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    collectionRid,
                    partitionedQueryExecutionInfo,
                    partitionKeyRanges,
                    initialPageSize,
                    continuationToken);

                return(await CosmosOrderByItemQueryExecutionContext.CreateAsync(
                           constructorParams,
                           initParams,
                           cancellationToken));
            };

            Func <string, Task <IDocumentQueryExecutionComponent> > createParallelComponentFunc = async(continuationToken) =>
            {
                CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    collectionRid,
                    partitionedQueryExecutionInfo,
                    partitionKeyRanges,
                    initialPageSize,
                    continuationToken);

                return(await CosmosParallelItemQueryExecutionContext.CreateAsync(
                           constructorParams,
                           initParams,
                           cancellationToken));
            };

            return((CosmosQueryExecutionContext)(await PipelinedDocumentQueryExecutionContext.CreateHelperAsync(
                                                     partitionedQueryExecutionInfo.QueryInfo,
                                                     initialPageSize,
                                                     requestContinuation,
                                                     createOrderByComponentFunc,
                                                     createParallelComponentFunc)));
        }
예제 #17
0
 /// <summary>
 /// Initializes a new instance of the CosmosParallelItemQueryExecutionContext class.
 /// </summary>
 /// <param name="queryContext">The parameters for constructing the base class.</param>
 /// <param name="maxConcurrency">The max concurrency</param>
 /// <param name="maxBufferedItemCount">The max buffered item count</param>
 /// <param name="maxItemCount">Max item count</param>
 private CosmosParallelItemQueryExecutionContext(
     CosmosQueryContext queryContext,
     int?maxConcurrency,
     int?maxItemCount,
     int?maxBufferedItemCount)
     : base(
         queryContext: queryContext,
         maxConcurrency: maxConcurrency,
         maxItemCount: maxItemCount,
         maxBufferedItemCount: maxBufferedItemCount,
         moveNextComparer: CosmosParallelItemQueryExecutionContext.MoveNextComparer,
         fetchPrioirtyFunction: CosmosParallelItemQueryExecutionContext.FetchPriorityFunction,
         equalityComparer: CosmosParallelItemQueryExecutionContext.EqualityComparer)
 {
 }
        public CosmosGatewayQueryExecutionContext(
            CosmosQueryContext cosmosQueryContext)
        {
            if (cosmosQueryContext == null)
            {
                throw new ArgumentNullException(nameof(cosmosQueryContext));
            }

            this.queryContext           = cosmosQueryContext;
            this.fetchSchedulingMetrics = new SchedulingStopwatch();
            this.fetchSchedulingMetrics.Ready();
            this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator();
            this.retries = -1;
            this.partitionRoutingHelper = new PartitionRoutingHelper();
        }
 /// <summary>
 /// Initializes a new instance of the CosmosOrderByItemQueryExecutionContext class.
 /// </summary>
 /// <param name="initPararms">The params used to construct the base class.</param>
 /// For cross partition order by queries a query like "SELECT c.id, c.field_0 ORDER BY r.field_7 gets rewritten as:
 /// <![CDATA[
 /// SELECT r._rid, [{"item": r.field_7}] AS orderByItems, {"id": r.id, "field_0": r.field_0} AS payload
 /// FROM r
 /// WHERE({ document db - formattable order by query - filter})
 /// ORDER BY r.field_7]]>
 /// This is needed because we need to add additional filters to the query when we resume from a continuation,
 /// and it lets us easily parse out the _rid orderByItems, and payload without parsing the entire document (and having to remember the order by field).
 /// <param name="maxConcurrency">The max concurrency</param>
 /// <param name="maxBufferedItemCount">The max buffered item count</param>
 /// <param name="maxItemCount">Max item count</param>
 /// <param name="consumeComparer">Comparer used to internally compare documents from different sorted partitions.</param>
 private CosmosOrderByItemQueryExecutionContext(
     CosmosQueryContext initPararms,
     int?maxConcurrency,
     int?maxItemCount,
     int?maxBufferedItemCount,
     OrderByConsumeComparer consumeComparer)
     : base(
         queryContext: initPararms,
         maxConcurrency: maxConcurrency,
         maxItemCount: maxItemCount,
         maxBufferedItemCount: maxBufferedItemCount,
         moveNextComparer: consumeComparer,
         fetchPrioirtyFunction: CosmosOrderByItemQueryExecutionContext.FetchPriorityFunction,
         equalityComparer: new OrderByEqualityComparer(consumeComparer))
 {
 }
        public CosmosProxyItemQueryExecutionContext(
            CosmosQueryContext queryContext,
            CosmosContainerSettings containerSettings)
        {
            if (queryContext == null)
            {
                throw new ArgumentNullException(nameof(queryContext));
            }

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

            this.innerExecutionContext = new CosmosGatewayQueryExecutionContext(queryContext);
            this.queryContext          = queryContext;
            this.containerSettings     = containerSettings;
        }
        /// <summary>
        /// Initializes a new instance of the CosmosCrossPartitionQueryExecutionContext class.
        /// </summary>
        /// <param name="queryContext">Constructor parameters for the base class.</param>
        /// <param name="maxConcurrency">The max concurrency</param>
        /// <param name="maxBufferedItemCount">The max buffered item count</param>
        /// <param name="maxItemCount">Max item count</param>
        /// <param name="moveNextComparer">Comparer used to figure out that document producer tree to serve documents from next.</param>
        /// <param name="fetchPrioirtyFunction">The priority function to determine which partition to fetch documents from next.</param>
        /// <param name="equalityComparer">Used to determine whether we need to return the continuation token for a partition.</param>
        protected CosmosCrossPartitionQueryExecutionContext(
            CosmosQueryContext queryContext,
            int?maxConcurrency,
            int?maxItemCount,
            int?maxBufferedItemCount,
            IComparer <ItemProducerTree> moveNextComparer,
            Func <ItemProducerTree, int> fetchPrioirtyFunction,
            IEqualityComparer <CosmosElement> equalityComparer)
        {
            if (moveNextComparer == null)
            {
                throw new ArgumentNullException(nameof(moveNextComparer));
            }

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

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

            this.queryContext            = queryContext ?? throw new ArgumentNullException(nameof(queryContext));
            this.queryClient             = queryContext.QueryClient ?? throw new ArgumentNullException(nameof(queryContext.QueryClient));
            this.itemProducerForest      = new PriorityQueue <ItemProducerTree>(moveNextComparer, isSynchronized: true);
            this.fetchPrioirtyFunction   = fetchPrioirtyFunction;
            this.comparableTaskScheduler = new ComparableTaskScheduler(maxConcurrency.GetValueOrDefault(0));
            this.equalityComparer        = equalityComparer;
            this.requestChargeTracker    = new RequestChargeTracker();
            this.diagnosticsPages        = new ConcurrentBag <QueryPageDiagnostics>();
            this.actualMaxPageSize       = maxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalMaxItemCount);

            if (this.actualMaxPageSize < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be less than 0");
            }

            if (this.actualMaxPageSize > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxPageSize should never be greater than int.MaxValue");
            }

            if (maxBufferedItemCount.HasValue)
            {
                this.actualMaxBufferedItemCount = maxBufferedItemCount.Value;
            }
            else
            {
                this.actualMaxBufferedItemCount = ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize;
            }

            if (this.actualMaxBufferedItemCount < 0)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be less than 0");
            }

            if (this.actualMaxBufferedItemCount > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("actualMaxBufferedItemCount should never be greater than int.MaxValue");
            }

            this.CanPrefetch = maxConcurrency.HasValue && maxConcurrency.Value != 0;
        }
        public CosmosQueryExecutionContextFactory(
            CosmosQueryClient client,
            ResourceType resourceTypeEnum,
            OperationType operationType,
            Type resourceType,
            SqlQuerySpec sqlQuerySpec,
            QueryRequestOptions queryRequestOptions,
            Uri resourceLink,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            Guid correlatedActivityId)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }

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

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

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

            // Prevent users from updating the values after creating the execution context.
            QueryRequestOptions cloneQueryRequestOptions = queryRequestOptions.Clone();

            // Swapping out negative values in feedOptions for int.MaxValue
            if (cloneQueryRequestOptions.MaxBufferedItemCount.HasValue && cloneQueryRequestOptions.MaxBufferedItemCount < 0)
            {
                cloneQueryRequestOptions.MaxBufferedItemCount = int.MaxValue;
            }

            if (cloneQueryRequestOptions.MaxConcurrency.HasValue && cloneQueryRequestOptions.MaxConcurrency < 0)
            {
                cloneQueryRequestOptions.MaxConcurrency = int.MaxValue;
            }

            if (cloneQueryRequestOptions.MaxItemCount.HasValue && cloneQueryRequestOptions.MaxItemCount < 0)
            {
                cloneQueryRequestOptions.MaxItemCount = int.MaxValue;
            }

            this.cosmosQueryContext = new CosmosQueryContext(
                client: client,
                resourceTypeEnum: resourceTypeEnum,
                operationType: operationType,
                resourceType: resourceType,
                sqlQuerySpecFromUser: sqlQuerySpec,
                queryRequestOptions: cloneQueryRequestOptions,
                resourceLink: resourceLink,
                getLazyFeedResponse: isContinuationExpected,
                isContinuationExpected: isContinuationExpected,
                allowNonValueAggregateQuery: allowNonValueAggregateQuery,
                correlatedActivityId: correlatedActivityId);
        }
        public static async Task <CosmosQueryExecutionContext> CreateSpecializedDocumentQueryExecutionContextAsync(
            CosmosQueryContext cosmosQueryContext,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            List <PartitionKeyRange> targetRanges,
            string collectionRid,
            CancellationToken cancellationToken)
        {
            if (!string.IsNullOrEmpty(partitionedQueryExecutionInfo.QueryInfo?.RewrittenQuery))
            {
                cosmosQueryContext.SqlQuerySpec = new SqlQuerySpec(
                    partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery,
                    cosmosQueryContext.SqlQuerySpec.Parameters);
            }

            // Figure out the optimal page size.
            long initialPageSize = cosmosQueryContext.QueryRequestOptions.MaxItemCount.GetValueOrDefault(ParallelQueryConfig.GetConfig().ClientInternalPageSize);

            if (initialPageSize < -1 || initialPageSize == 0)
            {
                throw new BadRequestException(string.Format(CultureInfo.InvariantCulture, "Invalid MaxItemCount {0}", initialPageSize));
            }

            QueryInfo queryInfo = partitionedQueryExecutionInfo.QueryInfo;

            bool getLazyFeedResponse = queryInfo.HasTop;

            // We need to compute the optimal initial page size for order-by queries
            if (queryInfo.HasOrderBy)
            {
                int top;
                if (queryInfo.HasTop && (top = partitionedQueryExecutionInfo.QueryInfo.Top.Value) > 0)
                {
                    // All partitions should initially fetch about 1/nth of the top value.
                    long pageSizeWithTop = (long)Math.Min(
                        Math.Ceiling(top / (double)targetRanges.Count) * PageSizeFactorForTop,
                        top);

                    if (initialPageSize > 0)
                    {
                        initialPageSize = Math.Min(pageSizeWithTop, initialPageSize);
                    }
                    else
                    {
                        initialPageSize = pageSizeWithTop;
                    }
                }
                else if (cosmosQueryContext.IsContinuationExpected)
                {
                    if (initialPageSize < 0)
                    {
                        if (cosmosQueryContext.QueryRequestOptions.MaxBufferedItemCount.HasValue)
                        {
                            // Max of what the user is willing to buffer and the default (note this is broken if MaxBufferedItemCount = -1)
                            initialPageSize = Math.Max(cosmosQueryContext.QueryRequestOptions.MaxBufferedItemCount.Value, ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize);
                        }
                        else
                        {
                            initialPageSize = ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize;
                        }
                    }

                    initialPageSize = (long)Math.Min(
                        Math.Ceiling(initialPageSize / (double)targetRanges.Count) * PageSizeFactorForTop,
                        initialPageSize);
                }
            }

            Debug.Assert(initialPageSize > 0 && initialPageSize <= int.MaxValue,
                         string.Format(CultureInfo.InvariantCulture, "Invalid MaxItemCount {0}", initialPageSize));

            return(await PipelinedDocumentQueryExecutionContext.CreateAsync(
                       cosmosQueryContext,
                       collectionRid,
                       partitionedQueryExecutionInfo,
                       targetRanges,
                       (int)initialPageSize,
                       cosmosQueryContext.QueryRequestOptions.RequestContinuation,
                       cancellationToken));
        }
        private async Task <CosmosQueryExecutionContext> CreateItemQueryExecutionContextAsync(
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            CosmosContainerSettings containerSettings = await this.GetContainerSettingsAsync(cancellationToken);

            this.cosmosQueryContext.ContainerResourceId = containerSettings.ResourceId;

            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo;

            if (this.cosmosQueryContext.QueryClient.ByPassQueryParsing() && TestFlag)
            {
                // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop, so need to bypass in that case.
                // We are also now bypassing this for 32 bit host process running even on Windows as there are many 32 bit apps that will not work without this
                partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanThroughGatewayAsync(
                    this.cosmosQueryContext.QueryClient,
                    this.cosmosQueryContext.SqlQuerySpec,
                    this.cosmosQueryContext.ResourceLink,
                    cancellationToken);
            }
            else
            {
                //todo:elasticcollections this may rely on information from collection cache which is outdated
                //if collection is deleted/created with same name.
                //need to make it not rely on information from collection cache.
                PartitionKeyDefinition partitionKeyDefinition;
                object partitionKeyDefinitionObject;
                if (this.cosmosQueryContext.QueryRequestOptions?.Properties != null &&
                    this.cosmosQueryContext.QueryRequestOptions.Properties.TryGetValue(InternalPartitionKeyDefinitionProperty, out partitionKeyDefinitionObject))
                {
                    if (partitionKeyDefinitionObject is PartitionKeyDefinition definition)
                    {
                        partitionKeyDefinition = definition;
                    }
                    else
                    {
                        throw new ArgumentException(
                                  "partitionkeydefinition has invalid type",
                                  nameof(partitionKeyDefinitionObject));
                    }
                }
                else
                {
                    partitionKeyDefinition = containerSettings.PartitionKey;
                }

                partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanWithServiceInteropAsync(
                    this.cosmosQueryContext.QueryClient,
                    this.cosmosQueryContext.SqlQuerySpec,
                    partitionKeyDefinition,
                    cancellationToken);
            }

            List <PartitionKeyRange> targetRanges = await GetTargetPartitionKeyRangesAsync(
                this.cosmosQueryContext.QueryClient,
                this.cosmosQueryContext.ResourceLink.OriginalString,
                partitionedQueryExecutionInfo,
                containerSettings,
                this.cosmosQueryContext.QueryRequestOptions);

            CosmosQueryContext rewrittenComosQueryContext;

            if (!string.IsNullOrEmpty(partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery))
            {
                // We need pass down the rewritten query.
                SqlQuerySpec rewrittenQuerySpec = new SqlQuerySpec()
                {
                    QueryText  = partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery,
                    Parameters = this.cosmosQueryContext.SqlQuerySpec.Parameters
                };

                rewrittenComosQueryContext = new CosmosQueryContext(
                    this.cosmosQueryContext.QueryClient,
                    this.cosmosQueryContext.ResourceTypeEnum,
                    this.cosmosQueryContext.OperationTypeEnum,
                    this.cosmosQueryContext.ResourceType,
                    rewrittenQuerySpec,
                    this.cosmosQueryContext.QueryRequestOptions,
                    this.cosmosQueryContext.ResourceLink,
                    this.cosmosQueryContext.IsContinuationExpected,
                    this.cosmosQueryContext.CorrelatedActivityId,
                    this.cosmosQueryContext.IsContinuationExpected,
                    this.cosmosQueryContext.AllowNonValueAggregateQuery,
                    this.cosmosQueryContext.ContainerResourceId);
            }
            else
            {
                rewrittenComosQueryContext = this.cosmosQueryContext;
            }

            return(await CreateSpecializedDocumentQueryExecutionContextAsync(
                       rewrittenComosQueryContext,
                       partitionedQueryExecutionInfo,
                       targetRanges,
                       containerSettings.ResourceId,
                       cancellationToken));
        }
        /// <summary>
        /// Initializes a new instance of the ItemProducerTree class.
        /// </summary>
        /// <param name="queryContext">query context.</param>
        /// <param name="querySpecForInit">query spec init.</param>
        /// <param name="partitionKeyRange">The partition key range.</param>
        /// <param name="produceAsyncCompleteCallback">Callback to invoke once a fetch finishes.</param>
        /// <param name="itemProducerTreeComparer">Comparer to determine, which tree to produce from.</param>
        /// <param name="equalityComparer">Comparer to see if we need to return the continuation token for a partition.</param>
        /// <param name="deferFirstPage">Whether or not to defer fetching the first page.</param>
        /// <param name="collectionRid">The collection to drain from.</param>
        /// <param name="initialPageSize">The initial page size.</param>
        /// <param name="initialContinuationToken">The initial continuation token.</param>
        public ItemProducerTree(
            CosmosQueryContext queryContext,
            SqlQuerySpec querySpecForInit,
            PartitionKeyRange partitionKeyRange,
            Action <ItemProducerTree, int, double, QueryMetrics, long, CancellationToken> produceAsyncCompleteCallback,
            IComparer <ItemProducerTree> itemProducerTreeComparer,
            IEqualityComparer <CosmosElement> equalityComparer,
            bool deferFirstPage,
            string collectionRid,
            long initialPageSize            = 50,
            string initialContinuationToken = null)
        {
            if (queryContext == null)
            {
                throw new ArgumentNullException($"{nameof(queryContext)}");
            }

            if (itemProducerTreeComparer == null)
            {
                throw new ArgumentNullException($"{nameof(itemProducerTreeComparer)}");
            }

            if (produceAsyncCompleteCallback == null)
            {
                throw new ArgumentNullException($"{nameof(produceAsyncCompleteCallback)}");
            }

            if (itemProducerTreeComparer == null)
            {
                throw new ArgumentNullException($"{nameof(itemProducerTreeComparer)}");
            }

            if (equalityComparer == null)
            {
                throw new ArgumentNullException($"{nameof(equalityComparer)}");
            }

            if (string.IsNullOrEmpty(collectionRid))
            {
                throw new ArgumentException($"{nameof(collectionRid)} can not be null or empty.");
            }

            this.Root = new ItemProducer(
                queryContext,
                querySpecForInit,
                partitionKeyRange,
                (itemProducer, itemsBuffered, resourceUnitUsage, queryMetrics, requestLength, token) => produceAsyncCompleteCallback(this, itemsBuffered, resourceUnitUsage, queryMetrics, requestLength, token),
                equalityComparer,
                initialPageSize,
                initialContinuationToken);

            this.queryClient    = queryContext.QueryClient;
            this.children       = new PriorityQueue <ItemProducerTree>(itemProducerTreeComparer, true);
            this.deferFirstPage = deferFirstPage;
            this.collectionRid  = collectionRid;
            this.createItemProducerTreeCallback = ItemProducerTree.CreateItemProducerTreeCallback(
                queryContext,
                querySpecForInit,
                produceAsyncCompleteCallback,
                itemProducerTreeComparer,
                equalityComparer,
                deferFirstPage,
                collectionRid,
                initialPageSize);
            this.executeWithSplitProofingSemaphore = new SemaphoreSlim(1, 1);
        }
예제 #26
0
        /// <summary>
        /// Creates a CosmosPipelinedItemQueryExecutionContext.
        /// </summary>
        /// <param name="executionEnvironment">The environment to execute on.</param>
        /// <param name="queryContext">The parameters for constructing the base class.</param>
        /// <param name="initParams">The initial parameters</param>
        /// <param name="requestContinuationToken">The request continuation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on, which in turn returns a CosmosPipelinedItemQueryExecutionContext.</returns>
        public static async Task <CosmosQueryExecutionContext> CreateAsync(
            ExecutionEnvironment executionEnvironment,
            CosmosQueryContext queryContext,
            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams,
            string requestContinuationToken,
            CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (requestContinuationToken != null)
            {
                if (!PipelineContinuationToken.TryParse(
                        requestContinuationToken,
                        out PipelineContinuationToken pipelineContinuationToken))
                {
                    throw queryContext.QueryClient.CreateBadRequestException(
                              $"Malformed {nameof(PipelineContinuationToken)}: {requestContinuationToken}.");
                }

                if (PipelineContinuationToken.IsTokenFromTheFuture(pipelineContinuationToken))
                {
                    throw queryContext.QueryClient.CreateBadRequestException(
                              $"{nameof(PipelineContinuationToken)} Continuation token is from a newer version of the SDK. Upgrade the SDK to avoid this issue.\n {requestContinuationToken}.");
                }

                if (!PipelineContinuationToken.TryConvertToLatest(
                        pipelineContinuationToken,
                        out PipelineContinuationTokenV1_1 latestVersionPipelineContinuationToken))
                {
                    throw queryContext.QueryClient.CreateBadRequestException(
                              $"{nameof(PipelineContinuationToken)}: '{requestContinuationToken}' is no longer supported.");
                }

                requestContinuationToken = latestVersionPipelineContinuationToken.SourceContinuationToken;
            }

            QueryInfo queryInfo = initParams.PartitionedQueryExecutionInfo.QueryInfo;

            int initialPageSize = initParams.InitialPageSize;

            CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams parameters = initParams;
            if (queryInfo.HasGroupBy)
            {
                // The query will block until all groupings are gathered so we might as well speed up the process.
                initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    sqlQuerySpec: initParams.SqlQuerySpec,
                    collectionRid: initParams.CollectionRid,
                    partitionedQueryExecutionInfo: initParams.PartitionedQueryExecutionInfo,
                    partitionKeyRanges: initParams.PartitionKeyRanges,
                    initialPageSize: int.MaxValue,
                    maxConcurrency: initParams.MaxConcurrency,
                    maxItemCount: int.MaxValue,
                    maxBufferedItemCount: initParams.MaxBufferedItemCount);
            }

            Func <string, Task <IDocumentQueryExecutionComponent> > createOrderByComponentFunc = async(continuationToken) =>
            {
                return(await CosmosOrderByItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            Func <string, Task <IDocumentQueryExecutionComponent> > createParallelComponentFunc = async(continuationToken) =>
            {
                return(await CosmosParallelItemQueryExecutionContext.CreateAsync(
                           queryContext,
                           initParams,
                           continuationToken,
                           cancellationToken));
            };

            return((CosmosQueryExecutionContext)await PipelinedDocumentQueryExecutionContext.CreateHelperAsync(
                       executionEnvironment,
                       queryContext.QueryClient,
                       initParams.PartitionedQueryExecutionInfo.QueryInfo,
                       initialPageSize,
                       requestContinuationToken,
                       createOrderByComponentFunc,
                       createParallelComponentFunc));
        }
        public override async Task <ResponseMessage> ReadNextAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            // This catches exception thrown by the pipeline and converts it to QueryResponse
            ResponseMessage response;

            try
            {
                QueryResponseCore responseCore = await this.cosmosQueryExecutionContext.ExecuteNextAsync(cancellationToken);

                CosmosQueryContext cosmosQueryContext = this.cosmosQueryExecutionContext.CosmosQueryContext;
                QueryResponse      queryResponse;
                if (responseCore.IsSuccess)
                {
                    queryResponse = QueryResponse.CreateSuccess(
                        result: responseCore.CosmosElements,
                        count: responseCore.CosmosElements.Count,
                        responseLengthBytes: responseCore.ResponseLengthBytes,
                        queryMetrics: responseCore.QueryMetrics,
                        responseHeaders: new CosmosQueryResponseMessageHeaders(
                            responseCore.ContinuationToken,
                            responseCore.DisallowContinuationTokenMessage,
                            cosmosQueryContext.ResourceTypeEnum,
                            cosmosQueryContext.ContainerResourceId)
                    {
                        RequestCharge = responseCore.RequestCharge,
                        ActivityId    = responseCore.ActivityId
                    });
                }
                else
                {
                    queryResponse = QueryResponse.CreateFailure(
                        statusCode: responseCore.StatusCode,
                        error: null,
                        errorMessage: responseCore.ErrorMessage,
                        requestMessage: null,
                        responseHeaders: new CosmosQueryResponseMessageHeaders(
                            responseCore.ContinuationToken,
                            responseCore.DisallowContinuationTokenMessage,
                            cosmosQueryContext.ResourceTypeEnum,
                            cosmosQueryContext.ContainerResourceId)
                    {
                        RequestCharge = responseCore.RequestCharge,
                        ActivityId    = responseCore.ActivityId
                    });
                }

                if (responseCore.QueryMetrics != null && responseCore.QueryMetrics.Count > 0)
                {
                    queryResponse.Diagnostics = new QueryOperationStatistics(responseCore.QueryMetrics);
                }

                queryResponse.CosmosSerializationOptions = cosmosQueryContext.QueryRequestOptions.CosmosSerializationFormatOptions;

                response = queryResponse;
            }
            catch (Documents.DocumentClientException exception)
            {
                response = exception.ToCosmosResponseMessage(request: null);
            }
            catch (CosmosException exception)
            {
                response = exception.ToCosmosResponseMessage(request: null);
            }
            catch (AggregateException ae)
            {
                response = TransportHandler.AggregateExceptionConverter(ae, null);
                if (response == null)
                {
                    throw;
                }
            }

            return(response);
        }
예제 #28
0
        /// <summary>
        /// Creates a CosmosPipelinedItemQueryExecutionContext.
        /// </summary>
        /// <param name="constructorParams">The parameters for constructing the base class.</param>
        /// <param name="collectionRid">The collection rid.</param>
        /// <param name="partitionedQueryExecutionInfo">The partitioned query execution info.</param>
        /// <param name="partitionKeyRanges">The partition key ranges.</param>
        /// <param name="initialPageSize">The initial page size.</param>
        /// <param name="requestContinuation">The request continuation.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task to await on, which in turn returns a CosmosPipelinedItemQueryExecutionContext.</returns>
        public static async Task <IDocumentQueryExecutionContext> CreateAsync(
            CosmosQueryContext constructorParams,
            string collectionRid,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            List <PartitionKeyRange> partitionKeyRanges,
            int initialPageSize,
            string requestContinuation,
            CancellationToken cancellationToken)
        {
            DefaultTrace.TraceInformation(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "{0}, CorrelatedActivityId: {1} | Pipelined~Context.CreateAsync",
                    DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture),
                    constructorParams.CorrelatedActivityId));

            Func <string, Task <IDocumentQueryExecutionComponent> > createComponentFunc;
            QueryInfo queryInfo = partitionedQueryExecutionInfo.QueryInfo;

            if (queryInfo.HasOrderBy)
            {
                createComponentFunc = async(continuationToken) =>
                {
                    CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                        collectionRid,
                        partitionedQueryExecutionInfo,
                        partitionKeyRanges,
                        initialPageSize,
                        continuationToken);

                    return(await CosmosOrderByItemQueryExecutionContext.CreateAsync(
                               constructorParams,
                               initParams,
                               cancellationToken));
                };
            }
            else
            {
                createComponentFunc = async(continuationToken) =>
                {
                    CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                        collectionRid,
                        partitionedQueryExecutionInfo,
                        partitionKeyRanges,
                        initialPageSize,
                        continuationToken);

                    return(await CosmosParallelItemQueryExecutionContext.CreateAsync(
                               constructorParams,
                               initParams,
                               cancellationToken));
                };
            }

            if (queryInfo.HasAggregates)
            {
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback = createComponentFunc;
                createComponentFunc = async(continuationToken) =>
                {
                    return(await AggregateDocumentQueryExecutionComponent.CreateAsync(
                               queryInfo.Aggregates,
                               continuationToken,
                               createSourceCallback));
                };
            }

            if (queryInfo.HasDistinct)
            {
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback = createComponentFunc;
                createComponentFunc = async(continuationToken) =>
                {
                    return(await DistinctDocumentQueryExecutionComponent.CreateAsync(
                               continuationToken,
                               createSourceCallback,
                               queryInfo.DistinctType));
                };
            }

            if (queryInfo.HasOffset)
            {
                if (!constructorParams.QueryRequestOptions.EnableCrossPartitionSkipTake)
                {
                    throw new ArgumentException("Cross Partition OFFSET / LIMIT is not supported.");
                }

                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback = createComponentFunc;
                createComponentFunc = async(continuationToken) =>
                {
                    return(await SkipDocumentQueryExecutionComponent.CreateAsync(
                               queryInfo.Offset.Value,
                               continuationToken,
                               createSourceCallback));
                };
            }

            if (queryInfo.HasLimit)
            {
                if (!constructorParams.QueryRequestOptions.EnableCrossPartitionSkipTake)
                {
                    throw new ArgumentException("Cross Partition OFFSET / LIMIT is not supported.");
                }

                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback = createComponentFunc;
                createComponentFunc = async(continuationToken) =>
                {
                    return(await TakeDocumentQueryExecutionComponent.CreateLimitDocumentQueryExecutionComponentAsync(
                               queryInfo.Limit.Value,
                               continuationToken,
                               createSourceCallback));
                };
            }

            if (queryInfo.HasTop)
            {
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback = createComponentFunc;
                createComponentFunc = async(continuationToken) =>
                {
                    return(await TakeDocumentQueryExecutionComponent.CreateTopDocumentQueryExecutionComponentAsync(
                               queryInfo.Top.Value,
                               continuationToken,
                               createSourceCallback));
                };
            }

            return(new CosmosPipelinedItemQueryExecutionContext(
                       await createComponentFunc(requestContinuation), initialPageSize));
        }