/// <summary>
        /// Gets the list of partition key ranges.
        /// 1. Check partition key range id
        /// 2. Check Partition key
        /// 3. Check the effective partition key
        /// 4. Get the range from the PartitionedQueryExecutionInfo
        /// </summary>
        internal static async Task <List <Documents.PartitionKeyRange> > GetTargetPartitionKeyRangesAsync(
            CosmosQueryClient queryClient,
            string resourceLink,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            ContainerQueryProperties containerQueryProperties,
            IDictionary <string, object> properties)
        {
            List <Documents.PartitionKeyRange> targetRanges;

            if (containerQueryProperties.EffectivePartitionKeyString != null)
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                    resourceLink,
                    containerQueryProperties.ResourceId,
                    containerQueryProperties.EffectivePartitionKeyString);
            }
            else if (TryGetEpkProperty(properties, out string effectivePartitionKeyString))
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                    resourceLink,
                    containerQueryProperties.ResourceId,
                    effectivePartitionKeyString);
            }
            else
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesAsync(
                    resourceLink,
                    containerQueryProperties.ResourceId,
                    partitionedQueryExecutionInfo.QueryRanges);
            }

            return(targetRanges);
        }
Exemple #2
0
        /// <summary>
        /// Gets the list of partition key ranges.
        /// 1. Check partition key range id
        /// 2. Check Partition key
        /// 3. Check the effective partition key
        /// 4. Get the range from the PartitionedQueryExecutionInfo
        /// </summary>
        internal static async Task <List <PartitionKeyRange> > GetTargetPartitionKeyRanges(
            CosmosQueryClient queryClient,
            string resourceLink,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            CosmosContainerSettings collection,
            CosmosQueryRequestOptions queryRequestOptions)
        {
            List <PartitionKeyRange> targetRanges;

            if (queryRequestOptions.PartitionKey != null)
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesByEpkString(
                    resourceLink,
                    collection.ResourceId,
                    new PartitionKey(queryRequestOptions.PartitionKey).InternalKey.GetEffectivePartitionKeyString(collection.PartitionKey));
            }
            else if (TryGetEpkProperty(queryRequestOptions, out string effectivePartitionKeyString))
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesByEpkString(
                    resourceLink,
                    collection.ResourceId,
                    effectivePartitionKeyString);
            }
            else
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRanges(
                    resourceLink,
                    collection.ResourceId,
                    partitionedQueryExecutionInfo.QueryRanges);
            }

            return(targetRanges);
        }
 private static bool ShouldCreateSpecializedDocumentQueryExecutionContext(
     ResourceType resourceTypeEnum,
     FeedOptions feedOptions,
     PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
     PartitionKeyDefinition partitionKeyDefinition,
     bool isContinuationExpected)
 {
     // We need to aggregate the total results with Pipelined~Context if isContinuationExpected is false.
     return
         ((DocumentQueryExecutionContextFactory.IsCrossPartitionQuery(
               resourceTypeEnum,
               feedOptions,
               partitionKeyDefinition,
               partitionedQueryExecutionInfo) &&
           (DocumentQueryExecutionContextFactory.IsTopOrderByQuery(partitionedQueryExecutionInfo) ||
            DocumentQueryExecutionContextFactory.IsAggregateQuery(partitionedQueryExecutionInfo) ||
            DocumentQueryExecutionContextFactory.IsOffsetLimitQuery(partitionedQueryExecutionInfo) ||
            DocumentQueryExecutionContextFactory.IsParallelQuery(feedOptions)) ||
           !string.IsNullOrEmpty(feedOptions.PartitionKeyRangeId)) ||
          // Even if it's single partition query we create a specialized context to aggregate the aggregates and distinct of distinct.
          DocumentQueryExecutionContextFactory.IsAggregateQueryWithoutContinuation(
              partitionedQueryExecutionInfo,
              isContinuationExpected) ||
          DocumentQueryExecutionContextFactory.IsDistinctQuery(partitionedQueryExecutionInfo) ||
          DocumentQueryExecutionContextFactory.IsGroupByQuery(partitionedQueryExecutionInfo));
 }
        public TryCatch <PartitionedQueryExecutionInfo> TryGetPartitionedQueryExecutionInfo(
            SqlQuerySpec querySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool requireFormattableOrderByQuery,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            bool hasLogicalPartitionKey)
        {
            TryCatch <PartitionedQueryExecutionInfoInternal> tryGetInternalQueryInfo = this.TryGetPartitionedQueryExecutionInfoInternal(
                querySpec,
                partitionKeyDefinition,
                requireFormattableOrderByQuery,
                isContinuationExpected,
                allowNonValueAggregateQuery,
                hasLogicalPartitionKey);

            if (!tryGetInternalQueryInfo.Succeeded)
            {
                return(TryCatch <PartitionedQueryExecutionInfo> .FromException(tryGetInternalQueryInfo.Exception));
            }

            PartitionedQueryExecutionInfo queryInfo = this.ConvertPartitionedQueryExecutionInfo(tryGetInternalQueryInfo.Result, partitionKeyDefinition);

            return(TryCatch <PartitionedQueryExecutionInfo> .FromResult(queryInfo));
        }
Exemple #5
0
        public async Task <CosmosQueryExecutionContext> CreateFromPartitionedQuerExecutionInfoAsync(
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            ContainerQueryProperties containerQueryProperties,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();

            List <Documents.PartitionKeyRange> targetRanges = await CosmosQueryExecutionContextFactory.GetTargetPartitionKeyRangesAsync(
                this.CosmosQueryContext.QueryClient,
                this.CosmosQueryContext.ResourceLink.OriginalString,
                partitionedQueryExecutionInfo,
                containerQueryProperties,
                this.inputParameters.Properties);

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

            return(await CosmosQueryExecutionContextFactory.CreateSpecializedDocumentQueryExecutionContextAsync(
                       this.CosmosQueryContext,
                       this.inputParameters,
                       partitionedQueryExecutionInfo,
                       targetRanges,
                       containerQueryProperties.ResourceId,
                       cancellationToken));
        }
            /// <summary>
            /// Initializes a new instance of the InitParams struct.
            /// </summary>
            /// <param name="sqlQuerySpec">The Sql query spec</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="maxConcurrency">The max concurrency</param>
            /// <param name="maxBufferedItemCount">The max buffered item count</param>
            /// <param name="maxItemCount">Max item count</param>
            /// <param name="testSettings">Test settings.</param>
            public CrossPartitionInitParams(
                SqlQuerySpec sqlQuerySpec,
                string collectionRid,
                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
                List <PartitionKeyRange> partitionKeyRanges,
                int initialPageSize,
                int?maxConcurrency,
                int?maxItemCount,
                int?maxBufferedItemCount,
                TestInjections testSettings)
            {
                if (string.IsNullOrWhiteSpace(collectionRid))
                {
                    throw new ArgumentException($"{nameof(collectionRid)} can not be null, empty, or white space.");
                }

                if (partitionedQueryExecutionInfo == null)
                {
                    throw new ArgumentNullException($"{nameof(partitionedQueryExecutionInfo)} can not be null.");
                }

                if (partitionKeyRanges == null)
                {
                    throw new ArgumentNullException($"{nameof(partitionKeyRanges)} can not be null.");
                }

                foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges)
                {
                    if (partitionKeyRange == null)
                    {
                        throw new ArgumentNullException($"{nameof(partitionKeyRange)} can not be null.");
                    }
                }

                if (initialPageSize <= 0)
                {
                    throw new ArgumentOutOfRangeException($"{nameof(initialPageSize)} must be at least 1.");
                }

                if (sqlQuerySpec == null)
                {
                    throw new ArgumentNullException($"{nameof(sqlQuerySpec)} can not be null.");
                }

                //// Request continuation is allowed to be null
                this.SqlQuerySpec  = sqlQuerySpec;
                this.CollectionRid = collectionRid;
                this.PartitionedQueryExecutionInfo = partitionedQueryExecutionInfo;
                this.PartitionKeyRanges            = partitionKeyRanges;
                this.InitialPageSize      = initialPageSize;
                this.MaxBufferedItemCount = maxBufferedItemCount;
                this.MaxConcurrency       = maxConcurrency;
                this.MaxItemCount         = maxItemCount;
                this.TestSettings         = testSettings;
            }
        /// <summary>
        /// Creates a PipelinedDocumentQueryExecutionContext.
        /// </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 PipelinedDocumentQueryExecutionContext.</returns>
        public static async Task <IDocumentQueryExecutionContext> CreateDocumentQueryExecutionContextAsync(
            DocumentQueryExecutionContextBase.InitParams 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));

            QueryInfo queryInfo = partitionedQueryExecutionInfo.QueryInfo;

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

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

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

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

            return((IDocumentQueryExecutionContext)(await PipelinedDocumentQueryExecutionContext.CreateHelperAsync(
                                                        partitionedQueryExecutionInfo.QueryInfo,
                                                        initialPageSize,
                                                        requestContinuation,
                                                        createOrderByComponentFunc,
                                                        createParallelComponentFunc)));
        }
 private static bool IsCrossPartitionQuery(
     ResourceType resourceTypeEnum,
     FeedOptions feedOptions,
     PartitionKeyDefinition partitionKeyDefinition,
     PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
 {
     return(resourceTypeEnum.IsPartitioned() &&
            (feedOptions.PartitionKey == null && feedOptions.EnableCrossPartitionQuery) &&
            (partitionKeyDefinition.Paths.Count > 0) &&
            !(partitionedQueryExecutionInfo.QueryRanges.Count == 1 && partitionedQueryExecutionInfo.QueryRanges[0].IsSingleValue));
 }
        public async Task <FeedResponse <dynamic> > ExecuteNextAsync(CancellationToken token)
        {
            if (this.IsDone)
            {
                throw new InvalidOperationException(RMResources.DocumentQueryExecutionContextIsDone);
            }

            Error error = null;

            try
            {
                return(await this.innerExecutionContext.ExecuteNextAsync(token));
            }
            catch (DocumentClientException ex)
            {
                if (ex.StatusCode != HttpStatusCode.BadRequest || ex.GetSubStatus() != SubStatusCodes.CrossPartitionQueryNotServable)
                {
                    throw;
                }

                error = ex.Error;
            }

            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo =
                JsonConvert.DeserializeObject <PartitionedQueryExecutionInfo>(error.AdditionalErrorInfo);

            DefaultDocumentQueryExecutionContext queryExecutionContext =
                (DefaultDocumentQueryExecutionContext)this.innerExecutionContext;

            List <PartitionKeyRange> partitionKeyRanges =
                await
                queryExecutionContext.GetTargetPartitionKeyRanges(collection.ResourceId,
                                                                  partitionedQueryExecutionInfo.QueryRanges);

            this.innerExecutionContext = await DocumentQueryExecutionContextFactory.CreateSpecializedDocumentQueryExecutionContext(
                this.client,
                this.resourceTypeEnum,
                this.resourceType,
                this.expression,
                this.feedOptions,
                this.resourceLink,
                isContinuationExpected,
                partitionedQueryExecutionInfo,
                partitionKeyRanges,
                this.collection.ResourceId,
                token,
                this.correlatedActivityId);

            return(await this.innerExecutionContext.ExecuteNextAsync(token));
        }
        public async Task <FeedResponse <CosmosElement> > ExecuteNextAsync(CancellationToken token)
        {
            if (this.IsDone)
            {
                throw new InvalidOperationException(RMResources.DocumentQueryExecutionContextIsDone);
            }

            Error error;

            try
            {
                return(await this.innerExecutionContext.ExecuteNextAsync(token));
            }
            catch (CosmosException ex)
            {
                if (ex.StatusCode != HttpStatusCode.BadRequest || ex.SubStatusCode != (int)SubStatusCodes.CrossPartitionQueryNotServable)
                {
                    throw;
                }

                error = ex.Error;
            }

            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo =
                JsonConvert.DeserializeObject <PartitionedQueryExecutionInfo>(error.AdditionalErrorInfo);

            string rewrittenQuery = partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery;

            if (!string.IsNullOrEmpty(rewrittenQuery))
            {
                this.queryContext.SqlQuerySpec.QueryText = rewrittenQuery;
            }

            List <PartitionKeyRange> partitionKeyRanges =
                await this.queryContext.QueryClient.GetTargetPartitionKeyRanges(
                    this.queryContext.ResourceLink.OriginalString,
                    this.containerSettings.ResourceId,
                    partitionedQueryExecutionInfo.QueryRanges);

            this.innerExecutionContext = await CosmosQueryExecutionContextFactory.CreateSpecializedDocumentQueryExecutionContext(
                this.queryContext,
                partitionedQueryExecutionInfo,
                partitionKeyRanges,
                this.containerSettings.ResourceId,
                token);

            return(await this.innerExecutionContext.ExecuteNextAsync(token));
        }
Exemple #11
0
        public static async Task <OrderByDocumentQueryExecutionContext> CreateAsync(
            IDocumentQueryClient client,
            ResourceType resourceTypeEnum,
            Type resourceType,
            Expression expression,
            FeedOptions feedOptions,
            string resourceLink,
            string collectionRid,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            List <PartitionKeyRange> partitionKeyRanges,
            int initialPageSize,
            bool isContinuationExpected,
            bool getLazyFeedResponse,
            string requestContinuation,
            CancellationToken token,
            Guid correlatedActivityId)
        {
            Debug.Assert(
                partitionedQueryExecutionInfo.QueryInfo.HasOrderBy,
                "OrderBy~Context must have order by query info.");

            OrderByDocumentQueryExecutionContext context = new OrderByDocumentQueryExecutionContext(
                client,
                resourceTypeEnum,
                resourceType,
                expression,
                feedOptions,
                resourceLink,
                partitionedQueryExecutionInfo.QueryInfo.RewrittenQuery,
                isContinuationExpected,
                getLazyFeedResponse,
                new OrderByConsumeComparer(partitionedQueryExecutionInfo.QueryInfo.OrderBy),
                collectionRid,
                correlatedActivityId);

            await context.InitializeAsync(
                collectionRid,
                partitionedQueryExecutionInfo.QueryRanges,
                partitionKeyRanges,
                partitionedQueryExecutionInfo.QueryInfo.OrderBy,
                partitionedQueryExecutionInfo.QueryInfo.OrderByExpressions,
                initialPageSize,
                requestContinuation,
                token);

            return(context);
        }
        public static QueryIterator Create(
            CosmosQueryClient client,
            SqlQuerySpec sqlQuerySpec,
            string continuationToken,
            QueryRequestOptions queryRequestOptions,
            Uri resourceLink,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
        {
            if (queryRequestOptions == null)
            {
                queryRequestOptions = new QueryRequestOptions();
            }

            CosmosQueryContext context = new CosmosQueryContextCore(
                client: client,
                queryRequestOptions: queryRequestOptions,
                resourceTypeEnum: Documents.ResourceType.Document,
                operationType: Documents.OperationType.Query,
                resourceType: typeof(QueryResponseCore),
                resourceLink: resourceLink,
                isContinuationExpected: isContinuationExpected,
                allowNonValueAggregateQuery: allowNonValueAggregateQuery,
                correlatedActivityId: Guid.NewGuid());

            CosmosQueryExecutionContextFactory.InputParameters inputParams = new CosmosQueryExecutionContextFactory.InputParameters()
            {
                SqlQuerySpec = sqlQuerySpec,
                InitialUserContinuationToken = continuationToken,
                MaxBufferedItemCount         = queryRequestOptions.MaxBufferedItemCount,
                MaxConcurrency = queryRequestOptions.MaxConcurrency,
                MaxItemCount   = queryRequestOptions.MaxItemCount,
                PartitionKey   = queryRequestOptions.PartitionKey,
                Properties     = queryRequestOptions.Properties,
                PartitionedQueryExecutionInfo      = partitionedQueryExecutionInfo,
                ExecutionEnvironment               = queryRequestOptions.ExecutionEnvironment.GetValueOrDefault(Core.ExecutionContext.ExecutionEnvironment.Client),
                ResponseContinuationTokenLimitInKb = queryRequestOptions.ResponseContinuationTokenLimitInKb,
            };

            return(new QueryIterator(
                       new CosmosQueryExecutionContextFactory(
                           cosmosQueryContext: context,
                           inputParameters: inputParams),
                       queryRequestOptions.CosmosSerializationFormatOptions));
        }
Exemple #13
0
        public static QueryIterator Create(
            CosmosQueryClient client,
            SqlQuerySpec sqlQuerySpec,
            string continuationToken,
            QueryRequestOptions queryRequestOptions,
            Uri resourceLink,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
        {
            if (queryRequestOptions == null)
            {
                queryRequestOptions = new QueryRequestOptions();
            }

            CosmosQueryContext cosmosQueryContext = new CosmosQueryContextCore(
                client: client,
                queryRequestOptions: queryRequestOptions,
                resourceTypeEnum: Documents.ResourceType.Document,
                operationType: Documents.OperationType.Query,
                resourceType: typeof(QueryResponseCore),
                resourceLink: resourceLink,
                isContinuationExpected: isContinuationExpected,
                allowNonValueAggregateQuery: allowNonValueAggregateQuery,
                correlatedActivityId: Guid.NewGuid());

            CosmosQueryExecutionContextFactory.InputParameters inputParameters = new CosmosQueryExecutionContextFactory.InputParameters(
                sqlQuerySpec: sqlQuerySpec,
                initialUserContinuationToken: continuationToken,
                maxConcurrency: queryRequestOptions.MaxConcurrency,
                maxItemCount: queryRequestOptions.MaxItemCount,
                maxBufferedItemCount: queryRequestOptions.MaxBufferedItemCount,
                partitionKey: queryRequestOptions.PartitionKey,
                properties: queryRequestOptions.Properties,
                partitionedQueryExecutionInfo: partitionedQueryExecutionInfo,
                executionEnvironment: queryRequestOptions.ExecutionEnvironment,
                returnResultsInDeterministicOrder: queryRequestOptions.ReturnResultsInDeterministicOrder,
                testInjections: queryRequestOptions.TestSettings);

            return(new QueryIterator(
                       cosmosQueryContext,
                       CosmosQueryExecutionContextFactory.Create(cosmosQueryContext, inputParameters),
                       queryRequestOptions.CosmosSerializationFormatOptions,
                       queryRequestOptions));
        }
        public static bool TryParse(string serializedQueryPlan, out PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
        {
            if (serializedQueryPlan == null)
            {
                throw new ArgumentNullException(nameof(serializedQueryPlan));
            }

            try
            {
                partitionedQueryExecutionInfo = JsonConvert.DeserializeObject <PartitionedQueryExecutionInfo>(serializedQueryPlan);
                return(true);
            }
            catch (JsonException)
            {
                partitionedQueryExecutionInfo = default(PartitionedQueryExecutionInfo);
                return(false);
            }
        }
        /// <summary>
        /// Gets the list of partition key ranges.
        /// 1. Check partition key range id
        /// 2. Check Partition key
        /// 3. Check the effective partition key
        /// 4. Get the range from the PartitionedQueryExecutionInfo
        /// </summary>
        internal static async Task <List <PartitionKeyRange> > GetTargetPartitionKeyRangesAsync(
            CosmosQueryClient queryClient,
            string resourceLink,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            CosmosContainerSettings collection,
            QueryRequestOptions queryRequestOptions)
        {
            List <PartitionKeyRange> targetRanges;

            if (queryRequestOptions.PartitionKey != null)
            {
                // Dis-ambiguate the NonePK if used
                PartitionKeyInternal partitionKeyInternal = null;
                if (Object.ReferenceEquals(queryRequestOptions.PartitionKey, CosmosContainerSettings.NonePartitionKeyValue))
                {
                    partitionKeyInternal = collection.GetNoneValue();
                }
                else
                {
                    partitionKeyInternal = new PartitionKey(queryRequestOptions.PartitionKey).InternalKey;
                }

                targetRanges = await queryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                    resourceLink,
                    collection.ResourceId,
                    partitionKeyInternal.GetEffectivePartitionKeyString(collection.PartitionKey));
            }
            else if (TryGetEpkProperty(queryRequestOptions, out string effectivePartitionKeyString))
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                    resourceLink,
                    collection.ResourceId,
                    effectivePartitionKeyString);
            }
            else
            {
                targetRanges = await queryClient.GetTargetPartitionKeyRangesAsync(
                    resourceLink,
                    collection.ResourceId,
                    partitionedQueryExecutionInfo.QueryRanges);
            }

            return(targetRanges);
        }
Exemple #16
0
            /// <summary>
            /// Initializes a new instance of the InitParams struct.
            /// </summary>
            /// <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>
            public CrossPartitionInitParams(
                string collectionRid,
                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
                List <PartitionKeyRange> partitionKeyRanges,
                int initialPageSize,
                string requestContinuation)
            {
                if (string.IsNullOrWhiteSpace(collectionRid))
                {
                    throw new ArgumentException($"{nameof(collectionRid)} can not be null, empty, or white space.");
                }

                if (partitionedQueryExecutionInfo == null)
                {
                    throw new ArgumentNullException($"{nameof(partitionedQueryExecutionInfo)} can not be null.");
                }

                if (partitionKeyRanges == null)
                {
                    throw new ArgumentNullException($"{nameof(partitionKeyRanges)} can not be null.");
                }

                foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges)
                {
                    if (partitionKeyRange == null)
                    {
                        throw new ArgumentNullException($"{nameof(partitionKeyRange)} can not be null.");
                    }
                }

                if (initialPageSize <= 0)
                {
                    throw new ArgumentOutOfRangeException($"{nameof(initialPageSize)} must be atleast 1.");
                }

                //// Request continuation is allowed to be null

                this.CollectionRid = collectionRid;
                this.PartitionedQueryExecutionInfo = partitionedQueryExecutionInfo;
                this.PartitionKeyRanges            = partitionKeyRanges;
                this.InitialPageSize     = initialPageSize;
                this.RequestContinuation = requestContinuation;
            }
        public async Task <DocumentFeedResponse <CosmosElement> > ExecuteNextFeedResponseAsync(CancellationToken token)
        {
            if (this.IsDone)
            {
                throw new InvalidOperationException(RMResources.DocumentQueryExecutionContextIsDone);
            }

            Error error = null;

            try
            {
                return(await this.innerExecutionContext.ExecuteNextFeedResponseAsync(token));
            }
            catch (DocumentClientException ex)
            {
                if (ex.StatusCode != HttpStatusCode.BadRequest || ex.GetSubStatus() != SubStatusCodes.CrossPartitionQueryNotServable)
                {
                    throw;
                }

                error = ex.Error;
            }

            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo =
                JsonConvert.DeserializeObject <PartitionedQueryExecutionInfo>(error.AdditionalErrorInfo);

            DefaultDocumentQueryExecutionContext queryExecutionContext =
                (DefaultDocumentQueryExecutionContext)this.innerExecutionContext;

            List <PartitionKeyRange> partitionKeyRanges =
                await
                queryExecutionContext.GetTargetPartitionKeyRangesAsync(collection.ResourceId,
                                                                       partitionedQueryExecutionInfo.QueryRanges);

            DocumentQueryExecutionContextBase.InitParams constructorParams = new DocumentQueryExecutionContextBase.InitParams(this.client, this.resourceTypeEnum, this.resourceType, this.expression, this.feedOptions, this.resourceLink, false, correlatedActivityId);
            // Devnote this will get replace by the new v3 to v2 logic
            throw new NotSupportedException("v2 query excution context is currently not supported.");

            //return await this.innerExecutionContext.ExecuteNextFeedResponseAsync(token);
        }
        /// <summary>
        /// Gets the list of partition key ranges.
        /// 1. Check partition key range id
        /// 2. Check Partition key
        /// 3. Check the effective partition key
        /// 4. Get the range from the PartitionedQueryExecutionInfo
        /// </summary>
        internal static async Task <List <PartitionKeyRange> > GetTargetPartitionKeyRangesAsync(
            DefaultDocumentQueryExecutionContext queryExecutionContext,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
            ContainerProperties collection,
            FeedOptions feedOptions)
        {
            List <PartitionKeyRange> targetRanges = null;

            if (!string.IsNullOrEmpty(feedOptions.PartitionKeyRangeId))
            {
                targetRanges = new List <PartitionKeyRange>()
                {
                    await queryExecutionContext.GetTargetPartitionKeyRangeByIdAsync(
                        collection.ResourceId,
                        feedOptions.PartitionKeyRangeId)
                };
            }
            else if (feedOptions.PartitionKey != null)
            {
                targetRanges = await queryExecutionContext.GetTargetPartitionKeyRangesByEpkStringAsync(
                    collection.ResourceId,
                    feedOptions.PartitionKey.InternalKey.GetEffectivePartitionKeyString(collection.PartitionKey));
            }
            else if (TryGetEpkProperty(feedOptions, out string effectivePartitionKeyString))
            {
                targetRanges = await queryExecutionContext.GetTargetPartitionKeyRangesByEpkStringAsync(
                    collection.ResourceId,
                    effectivePartitionKeyString);
            }
            else
            {
                targetRanges = await queryExecutionContext.GetTargetPartitionKeyRangesAsync(
                    collection.ResourceId,
                    partitionedQueryExecutionInfo.QueryRanges);
            }

            return(targetRanges);
        }
        public static async Task <IDocumentQueryExecutionContext> CreateDocumentQueryExecutionContextAsync(
            IDocumentQueryClient client,
            ResourceType resourceTypeEnum,
            Type resourceType,
            Expression expression,
            FeedOptions feedOptions,
            string resourceLink,
            bool isContinuationExpected,
            CancellationToken token,
            Guid correlatedActivityId)
        {
            ContainerProperties collection = null;

            if (resourceTypeEnum.IsCollectionChild())
            {
                CollectionCache collectionCache = await client.GetCollectionCacheAsync();

                using (
                    DocumentServiceRequest request = DocumentServiceRequest.Create(
                        OperationType.Query,
                        resourceTypeEnum,
                        resourceLink,
                        AuthorizationTokenType.Invalid)) //this request doesnt actually go to server
                {
                    collection = await collectionCache.ResolveCollectionAsync(request, token);
                }

                if (feedOptions != null && feedOptions.PartitionKey != null && feedOptions.PartitionKey.Equals(Documents.PartitionKey.None))
                {
                    feedOptions.PartitionKey = Documents.PartitionKey.FromInternalKey(collection.GetNoneValue());
                }
            }

            DocumentQueryExecutionContextBase.InitParams constructorParams = new DocumentQueryExecutionContextBase.InitParams(
                client,
                resourceTypeEnum,
                resourceType,
                expression,
                feedOptions,
                resourceLink,
                false,
                correlatedActivityId);

            // 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
            if (CustomTypeExtensions.ByPassQueryParsing())
            {
                // We create a ProxyDocumentQueryExecutionContext that will be initialized with DefaultDocumentQueryExecutionContext
                // which will be used to send the query to Gateway and on getting 400(bad request) with 1004(cross partition query not servable), we initialize it with
                // PipelinedDocumentQueryExecutionContext by providing the partition query execution info that's needed(which we get from the exception returned from Gateway).
                ProxyDocumentQueryExecutionContext proxyQueryExecutionContext =
                    ProxyDocumentQueryExecutionContext.Create(
                        client,
                        resourceTypeEnum,
                        resourceType,
                        expression,
                        feedOptions,
                        resourceLink,
                        token,
                        collection,
                        isContinuationExpected,
                        correlatedActivityId);

                return(proxyQueryExecutionContext);
            }

            DefaultDocumentQueryExecutionContext queryExecutionContext = await DefaultDocumentQueryExecutionContext.CreateAsync(
                constructorParams, isContinuationExpected, token);

            // If isContinuationExpected is false, we want to check if there are aggregates.
            if (
                resourceTypeEnum.IsCollectionChild() &&
                resourceTypeEnum.IsPartitioned() &&
                (feedOptions.EnableCrossPartitionQuery || !isContinuationExpected))
            {
                //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.
                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = await queryExecutionContext.GetPartitionedQueryExecutionInfoAsync(
                    partitionKeyDefinition : collection.PartitionKey,
                    requireFormattableOrderByQuery : true,
                    isContinuationExpected : isContinuationExpected,
                    allowNonValueAggregateQuery : true,
                    hasLogicalPartitionKey : feedOptions.PartitionKey != null,
                    cancellationToken : token);

                if (DocumentQueryExecutionContextFactory.ShouldCreateSpecializedDocumentQueryExecutionContext(
                        resourceTypeEnum,
                        feedOptions,
                        partitionedQueryExecutionInfo,
                        collection.PartitionKey,
                        isContinuationExpected))
                {
                    List <PartitionKeyRange> targetRanges = await GetTargetPartitionKeyRangesAsync(
                        queryExecutionContext,
                        partitionedQueryExecutionInfo,
                        collection,
                        feedOptions);

                    // Devnote this will get replace by the new v3 to v2 logic
                    throw new NotSupportedException("v2 query excution context is currently not supported.");
                }
            }

            return(queryExecutionContext);
        }
 private static bool IsOffsetLimitQuery(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
 {
     return(partitionedQueryExecutionInfo.QueryInfo.HasOffset && partitionedQueryExecutionInfo.QueryInfo.HasLimit);
 }
 private static bool IsAggregateQueryWithoutContinuation(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo, bool isContinuationExpected)
 {
     return(IsAggregateQuery(partitionedQueryExecutionInfo) && !isContinuationExpected);
 }
 private static bool IsAggregateQuery(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
 {
     return((partitionedQueryExecutionInfo.QueryInfo != null) &&
            (partitionedQueryExecutionInfo.QueryInfo.HasAggregates));
 }
 private static bool IsTopOrderByQuery(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
 {
     return((partitionedQueryExecutionInfo.QueryInfo != null) &&
            (partitionedQueryExecutionInfo.QueryInfo.HasOrderBy || partitionedQueryExecutionInfo.QueryInfo.HasTop));
 }
        /// <summary>
        /// Creates a PipelinedDocumentQueryExecutionContext.
        /// </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 PipelinedDocumentQueryExecutionContext.</returns>
        public static async Task <IDocumentQueryExecutionContext> CreateAsync(
            DocumentQueryExecutionContextBase.InitParams 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) =>
                {
                    CrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                        collectionRid,
                        partitionedQueryExecutionInfo,
                        partitionKeyRanges,
                        initialPageSize,
                        continuationToken);

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

                    return(await ParallelDocumentQueryExecutionContext.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.FeedOptions.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.FeedOptions.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 PipelinedDocumentQueryExecutionContext(
                       await createComponentFunc(requestContinuation), initialPageSize));
        }
        public static QueryIterator Create(
            CosmosQueryClient client,
            SqlQuerySpec sqlQuerySpec,
            string continuationToken,
            QueryRequestOptions queryRequestOptions,
            Uri resourceLink,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
        {
            if (queryRequestOptions == null)
            {
                queryRequestOptions = new QueryRequestOptions();
            }

            CosmosQueryContext cosmosQueryContext = new CosmosQueryContextCore(
                client: client,
                queryRequestOptions: queryRequestOptions,
                resourceTypeEnum: Documents.ResourceType.Document,
                operationType: Documents.OperationType.Query,
                resourceType: typeof(QueryResponseCore),
                resourceLink: resourceLink,
                isContinuationExpected: isContinuationExpected,
                allowNonValueAggregateQuery: allowNonValueAggregateQuery,
                correlatedActivityId: Guid.NewGuid());

            CosmosElement requestContinuationToken;

            switch (queryRequestOptions.ExecutionEnvironment.GetValueOrDefault(ExecutionEnvironment.Client))
            {
            case ExecutionEnvironment.Client:
                if (continuationToken != null)
                {
                    if (!CosmosElement.TryParse(continuationToken, out requestContinuationToken))
                    {
                        return(new QueryIterator(
                                   cosmosQueryContext,
                                   new QueryExecutionContextWithException(
                                       new MalformedContinuationTokenException(
                                           $"Malformed Continuation Token: {requestContinuationToken}")),
                                   queryRequestOptions.CosmosSerializationFormatOptions,
                                   queryRequestOptions));
                    }
                }
                else
                {
                    requestContinuationToken = null;
                }
                break;

            case ExecutionEnvironment.Compute:
                requestContinuationToken = queryRequestOptions.CosmosElementContinuationToken;
                break;

            default:
                throw new ArgumentOutOfRangeException($"Unknown {nameof(ExecutionEnvironment)}: {queryRequestOptions.ExecutionEnvironment.Value}.");
            }

            CosmosQueryExecutionContextFactory.InputParameters inputParameters = new CosmosQueryExecutionContextFactory.InputParameters(
                sqlQuerySpec: sqlQuerySpec,
                initialUserContinuationToken: requestContinuationToken,
                maxConcurrency: queryRequestOptions.MaxConcurrency,
                maxItemCount: queryRequestOptions.MaxItemCount,
                maxBufferedItemCount: queryRequestOptions.MaxBufferedItemCount,
                partitionKey: queryRequestOptions.PartitionKey,
                properties: queryRequestOptions.Properties,
                partitionedQueryExecutionInfo: partitionedQueryExecutionInfo,
                executionEnvironment: queryRequestOptions.ExecutionEnvironment,
                returnResultsInDeterministicOrder: queryRequestOptions.ReturnResultsInDeterministicOrder,
                testInjections: queryRequestOptions.TestSettings);

            return(new QueryIterator(
                       cosmosQueryContext,
                       CosmosQueryExecutionContextFactory.Create(cosmosQueryContext, inputParameters),
                       queryRequestOptions.CosmosSerializationFormatOptions,
                       queryRequestOptions));
        }
        public static QueryIterator Create(
            ContainerCore containerCore,
            CosmosQueryClient client,
            CosmosClientContext clientContext,
            SqlQuerySpec sqlQuerySpec,
            string continuationToken,
            FeedRangeInternal feedRangeInternal,
            QueryRequestOptions queryRequestOptions,
            string resourceLink,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            bool forcePassthrough,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
        {
            if (queryRequestOptions == null)
            {
                queryRequestOptions = new QueryRequestOptions();
            }

            CosmosQueryContextCore cosmosQueryContext = new CosmosQueryContextCore(
                client: client,
                resourceTypeEnum: Documents.ResourceType.Document,
                operationType: Documents.OperationType.Query,
                resourceType: typeof(QueryResponseCore),
                resourceLink: resourceLink,
                isContinuationExpected: isContinuationExpected,
                allowNonValueAggregateQuery: allowNonValueAggregateQuery,
                correlatedActivityId: Guid.NewGuid());

            NetworkAttachedDocumentContainer networkAttachedDocumentContainer = new NetworkAttachedDocumentContainer(
                containerCore,
                client,
                queryRequestOptions);
            DocumentContainer documentContainer = new DocumentContainer(networkAttachedDocumentContainer);

            CosmosElement requestContinuationToken;

            switch (queryRequestOptions.ExecutionEnvironment.GetValueOrDefault(ExecutionEnvironment.Client))
            {
            case ExecutionEnvironment.Client:
                if (continuationToken != null)
                {
                    TryCatch <CosmosElement> tryParse = CosmosElement.Monadic.Parse(continuationToken);
                    if (tryParse.Failed)
                    {
                        return(new QueryIterator(
                                   cosmosQueryContext,
                                   new FaultedQueryPipelineStage(
                                       new MalformedContinuationTokenException(
                                           message: $"Malformed Continuation Token: {continuationToken}",
                                           innerException: tryParse.Exception)),
                                   queryRequestOptions.CosmosSerializationFormatOptions,
                                   queryRequestOptions,
                                   clientContext));
                    }

                    requestContinuationToken = tryParse.Result;
                }
                else
                {
                    requestContinuationToken = null;
                }
                break;

            case ExecutionEnvironment.Compute:
                requestContinuationToken = queryRequestOptions.CosmosElementContinuationToken;
                break;

            default:
                throw new ArgumentOutOfRangeException($"Unknown {nameof(ExecutionEnvironment)}: {queryRequestOptions.ExecutionEnvironment.Value}.");
            }

            CosmosQueryExecutionContextFactory.InputParameters inputParameters = new CosmosQueryExecutionContextFactory.InputParameters(
                sqlQuerySpec: sqlQuerySpec,
                initialUserContinuationToken: requestContinuationToken,
                initialFeedRange: feedRangeInternal,
                maxConcurrency: queryRequestOptions.MaxConcurrency,
                maxItemCount: queryRequestOptions.MaxItemCount,
                maxBufferedItemCount: queryRequestOptions.MaxBufferedItemCount,
                partitionKey: queryRequestOptions.PartitionKey,
                properties: queryRequestOptions.Properties,
                partitionedQueryExecutionInfo: partitionedQueryExecutionInfo,
                executionEnvironment: queryRequestOptions.ExecutionEnvironment,
                returnResultsInDeterministicOrder: queryRequestOptions.ReturnResultsInDeterministicOrder,
                forcePassthrough: forcePassthrough,
                testInjections: queryRequestOptions.TestSettings);

            return(new QueryIterator(
                       cosmosQueryContext,
                       CosmosQueryExecutionContextFactory.Create(documentContainer, cosmosQueryContext, inputParameters, NoOpTrace.Singleton),
                       queryRequestOptions.CosmosSerializationFormatOptions,
                       queryRequestOptions,
                       clientContext));
        }
 private static bool IsDistinctQuery(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
 {
     return(partitionedQueryExecutionInfo.QueryInfo.HasDistinct);
 }
        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 static bool IsGroupByQuery(PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
 {
     return(partitionedQueryExecutionInfo.QueryInfo.HasGroupBy);
 }
Exemple #30
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 <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));

            QueryInfo queryInfo = partitionedQueryExecutionInfo.QueryInfo;

            int actualPageSize = initialPageSize;

            if (queryInfo.HasGroupBy)
            {
                initialPageSize = int.MaxValue;
                constructorParams.QueryRequestOptions.MaxItemCount = int.MaxValue;
            }

            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,
                                                     constructorParams.QueryRequestOptions.EnableGroupBy,
                                                     createOrderByComponentFunc,
                                                     createParallelComponentFunc)));
        }