示例#1
0
        private GroupByDocumentQueryExecutionComponent(
            CosmosQueryClient cosmosQueryClient,
            IReadOnlyDictionary <string, AggregateOperator?> groupByAliasToAggregateType,
            IReadOnlyList <string> orderedAliases,
            bool hasSelectValue,
            IDocumentQueryExecutionComponent source)
            : base(source)
        {
            if (cosmosQueryClient == null)
            {
                throw new ArgumentNullException(nameof(cosmosQueryClient));
            }

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

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

            this.cosmosQueryClient           = cosmosQueryClient;
            this.groupingTable               = new Dictionary <UInt192, SingleGroupAggregator>();
            this.groupByAliasToAggregateType = groupByAliasToAggregateType;
            this.orderedAliases              = orderedAliases;
            this.hasSelectValue              = hasSelectValue;
        }
        /// <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>
        /// <param name="returnResultsInDeterministicOrder">Whether or not to return results in deterministic order.</param>
        /// <param name="testSettings">Test settings.</param>
        protected CosmosCrossPartitionQueryExecutionContext(
            CosmosQueryContext queryContext,
            int?maxConcurrency,
            int?maxItemCount,
            int?maxBufferedItemCount,
            IComparer <ItemProducerTree> moveNextComparer,
            Func <ItemProducerTree, int> fetchPrioirtyFunction,
            IEqualityComparer <CosmosElement> equalityComparer,
            bool returnResultsInDeterministicOrder,
            TestInjections testSettings)
        {
            if (moveNextComparer == null)
            {
                throw new ArgumentNullException(nameof(moveNextComparer));
            }

            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 ?? throw new ArgumentNullException(nameof(fetchPrioirtyFunction));
            this.comparableTaskScheduler = new ComparableTaskScheduler(maxConcurrency.GetValueOrDefault(0));
            this.equalityComparer        = equalityComparer ?? throw new ArgumentNullException(nameof(equalityComparer));
            this.testSettings            = testSettings;
            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;

            this.returnResultsInDeterministicOrder = returnResultsInDeterministicOrder;
        }
        public static async Task <TakeDocumentQueryExecutionComponent> CreateTopDocumentQueryExecutionComponentAsync(
            CosmosQueryClient queryClient,
            int topCount,
            string continuationToken,
            Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback)
        {
            if (queryClient == null)
            {
                throw new ArgumentNullException(nameof(queryClient));
            }

            TopContinuationToken topContinuationToken;

            if (continuationToken != null)
            {
                topContinuationToken = TopContinuationToken.Parse(queryClient, continuationToken);
            }
            else
            {
                topContinuationToken = new TopContinuationToken(topCount, null);
            }

            if (topContinuationToken.Top > topCount)
            {
                throw queryClient.CreateBadRequestException($"top count in continuation token: {topContinuationToken.Top} can not be greater than the top count in the query: {topCount}.");
            }

            return(new TakeDocumentQueryExecutionComponent(
                       await createSourceCallback(topContinuationToken.SourceToken),
                       topContinuationToken.Top,
                       TakeEnum.Top));
        }
        /// <summary>
        /// Creates an DistinctDocumentQueryExecutionComponent
        /// </summary>
        /// <param name="executionEnvironment">The environment to execute on.</param>
        /// <param name="queryClient">The query client</param>
        /// <param name="requestContinuation">The continuation token.</param>
        /// <param name="createSourceCallback">The callback to create the source to drain from.</param>
        /// <param name="distinctQueryType">The type of distinct query.</param>
        /// <returns>A task to await on and in return </returns>
        public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
            ExecutionEnvironment executionEnvironment,
            CosmosQueryClient queryClient,
            string requestContinuation,
            Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
            DistinctQueryType distinctQueryType)
        {
            IDocumentQueryExecutionComponent distinctDocumentQueryExecutionComponent;

            switch (executionEnvironment)
            {
            case ExecutionEnvironment.Client:
                distinctDocumentQueryExecutionComponent = await ClientDistinctDocumentQueryExecutionComponent.CreateAsync(
                    queryClient,
                    requestContinuation,
                    createSourceCallback,
                    distinctQueryType);

                break;

            case ExecutionEnvironment.Compute:
                distinctDocumentQueryExecutionComponent = await ComputeDistinctDocumentQueryExecutionComponent.CreateAsync(
                    queryClient,
                    requestContinuation,
                    createSourceCallback,
                    distinctQueryType);

                break;

            default:
                throw new ArgumentException($"Unknown {nameof(ExecutionEnvironment)}: {executionEnvironment}.");
            }

            return(distinctDocumentQueryExecutionComponent);
        }
        public static async Task <TakeDocumentQueryExecutionComponent> CreateLimitDocumentQueryExecutionComponentAsync(
            CosmosQueryClient queryClient,
            int limitCount,
            string continuationToken,
            Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback)
        {
            if (queryClient == null)
            {
                throw new ArgumentNullException(nameof(queryClient));
            }

            LimitContinuationToken limitContinuationToken;

            if (continuationToken != null)
            {
                limitContinuationToken = LimitContinuationToken.Parse(queryClient, continuationToken);
            }
            else
            {
                limitContinuationToken = new LimitContinuationToken(limitCount, null);
            }

            if (limitContinuationToken.Limit > limitCount)
            {
                throw queryClient.CreateBadRequestException($"limit count in continuation token: {limitContinuationToken.Limit} can not be greater than the limit count in the query: {limitCount}.");
            }

            return(new TakeDocumentQueryExecutionComponent(
                       await createSourceCallback(limitContinuationToken.SourceToken),
                       limitContinuationToken.Limit,
                       TakeEnum.Limit));
        }
        /// <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,
            IReadOnlyDictionary <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);
        }
            /// <summary>
            /// Creates an DistinctDocumentQueryExecutionComponent
            /// </summary>
            /// <param name="queryClient">The query client</param>
            /// <param name="requestContinuation">The continuation token.</param>
            /// <param name="createSourceCallback">The callback to create the source to drain from.</param>
            /// <param name="distinctQueryType">The type of distinct query.</param>
            /// <returns>A task to await on and in return </returns>
            public static async Task <DistinctDocumentQueryExecutionComponent> CreateAsync(
                CosmosQueryClient queryClient,
                string requestContinuation,
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
                DistinctQueryType distinctQueryType)
            {
                DistinctContinuationToken distinctContinuationToken;

                if (requestContinuation != null)
                {
                    if (!DistinctContinuationToken.TryParse(requestContinuation, out distinctContinuationToken))
                    {
                        throw queryClient.CreateBadRequestException($"Invalid {nameof(DistinctContinuationToken)}: {requestContinuation}");
                    }
                }
                else
                {
                    distinctContinuationToken = new DistinctContinuationToken(sourceToken: null, distinctMapToken: null);
                }

                DistinctMap distinctMap = DistinctMap.Create(distinctQueryType, distinctContinuationToken.DistinctMapToken);
                IDocumentQueryExecutionComponent source = await createSourceCallback(distinctContinuationToken.SourceToken);

                return(new ComputeDistinctDocumentQueryExecutionComponent(
                           distinctQueryType,
                           distinctMap,
                           source));
            }
示例#8
0
        public static Task <PartitionedQueryExecutionInfo> GetQueryPlanThroughGatewayAsync(
            CosmosQueryClient client,
            SqlQuerySpec sqlQuerySpec,
            Uri resourceLink,
            PartitionKey?partitionKey,
            CancellationToken cancellationToken = default)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }

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

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

            cancellationToken.ThrowIfCancellationRequested();

            return(client.ExecuteQueryPlanRequestAsync(
                       resourceLink,
                       ResourceType.Document,
                       OperationType.QueryPlan,
                       sqlQuerySpec,
                       partitionKey,
                       QueryPlanRetriever.SupportedQueryFeaturesString,
                       cancellationToken));
        }
示例#9
0
        public static async Task <PartitionedQueryExecutionInfo> GetQueryPlanWithServiceInteropAsync(
            CosmosQueryClient queryClient,
            SqlQuerySpec sqlQuerySpec,
            Documents.ResourceType resourceType,
            PartitionKeyDefinition partitionKeyDefinition,
            bool hasLogicalPartitionKey,
            bool useSystemPrefix,
            ITrace trace,
            CancellationToken cancellationToken = default)
        {
            if (queryClient == null)
            {
                throw new ArgumentNullException(nameof(queryClient));
            }

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

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

            cancellationToken.ThrowIfCancellationRequested();

            using (ITrace serviceInteropTrace = trace.StartChild("Service Interop Query Plan", TraceComponent.Query, TraceLevel.Info))
            {
                QueryPlanHandler queryPlanHandler = new QueryPlanHandler(queryClient);

                TryCatch <PartitionedQueryExecutionInfo> tryGetQueryPlan = await queryPlanHandler.TryGetQueryPlanAsync(
                    sqlQuerySpec,
                    resourceType,
                    partitionKeyDefinition,
                    QueryPlanRetriever.SupportedQueryFeatures,
                    hasLogicalPartitionKey,
                    useSystemPrefix,
                    cancellationToken);

                if (!tryGetQueryPlan.Succeeded)
                {
                    Exception originalException = ExceptionWithStackTraceException.UnWrapMonadExcepion(tryGetQueryPlan.Exception, serviceInteropTrace);
                    if (originalException is CosmosException)
                    {
                        throw originalException;
                    }

                    throw CosmosExceptionFactory.CreateBadRequestException(
                              message: originalException.Message,
                              headers: new Headers(),
                              stackTrace: tryGetQueryPlan.Exception.StackTrace,
                              innerException: originalException,
                              trace: trace);
                }

                return(tryGetQueryPlan.Result);
            }
        }
示例#10
0
 public NetworkAttachedDocumentContainer(
     ContainerCore container,
     CosmosQueryClient cosmosQueryClient,
     CosmosClientContext cosmosClientContext,
     CosmosDiagnosticsContext diagnosticsContext,
     QueryRequestOptions queryRequestOptions = null)
 {
     this.container           = container ?? throw new ArgumentNullException(nameof(container));
     this.cosmosQueryClient   = cosmosQueryClient ?? throw new ArgumentNullException(nameof(cosmosQueryClient));
     this.cosmosClientContext = cosmosClientContext ?? throw new ArgumentNullException(nameof(cosmosClientContext));
     this.diagnosticsContext  = diagnosticsContext;
     this.queryRequestOptions = queryRequestOptions;
 }
 public CosmosLinqQueryProvider(
     CosmosContainerCore container,
     CosmosJsonSerializer cosmosJsonSerializer,
     CosmosQueryClient queryClient,
     QueryRequestOptions cosmosQueryRequestOptions,
     bool allowSynchronousQueryExecution)
 {
     this.container                      = container;
     this.cosmosJsonSerializer           = cosmosJsonSerializer;
     this.queryClient                    = queryClient;
     this.cosmosQueryRequestOptions      = cosmosQueryRequestOptions;
     this.allowSynchronousQueryExecution = allowSynchronousQueryExecution;
 }
            /// <summary>
            /// Parses the TopContinuationToken from it's string form.
            /// </summary>
            /// <param name="queryClient">The query client</param>
            /// <param name="value">The string form to parse from.</param>
            /// <returns>The parsed TopContinuationToken.</returns>
            public static TopContinuationToken Parse(CosmosQueryClient queryClient, string value)
            {
                TopContinuationToken result;

                if (!TryParse(value, out result))
                {
                    throw queryClient.CreateBadRequestException($"Invalid TopContinuationToken: {value}");
                }
                else
                {
                    return(result);
                }
            }
示例#13
0
        public static async Task <PartitionedQueryExecutionInfo> GetQueryPlanWithServiceInteropAsync(
            CosmosQueryClient queryClient,
            SqlQuerySpec sqlQuerySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool hasLogicalPartitionKey,
            ITrace trace,
            CancellationToken cancellationToken = default)
        {
            if (queryClient == null)
            {
                throw new ArgumentNullException(nameof(queryClient));
            }

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

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

            cancellationToken.ThrowIfCancellationRequested();

            using (ITrace serviceInteropTrace = trace.StartChild("Service Interop Query Plan", TraceComponent.Query, TraceLevel.Info))
            {
                QueryPlanHandler queryPlanHandler = new QueryPlanHandler(queryClient);

                TryCatch <PartitionedQueryExecutionInfo> tryGetQueryPlan = await queryPlanHandler.TryGetQueryPlanAsync(
                    sqlQuerySpec,
                    partitionKeyDefinition,
                    QueryPlanRetriever.SupportedQueryFeatures,
                    hasLogicalPartitionKey,
                    cancellationToken);

                if (!tryGetQueryPlan.Succeeded)
                {
                    if (tryGetQueryPlan.Exception is CosmosException)
                    {
                        throw tryGetQueryPlan.Exception;
                    }

                    throw CosmosExceptionFactory.CreateBadRequestException(
                              message: tryGetQueryPlan.Exception.ToString(),
                              stackTrace: tryGetQueryPlan.Exception.StackTrace);
                }

                return(tryGetQueryPlan.Result);
            }
        }
示例#14
0
 public CosmosLinqQuery(
     CosmosContainerCore container,
     CosmosJsonSerializer cosmosJsonSerializer,
     CosmosQueryClient queryClient,
     QueryRequestOptions cosmosQueryRequestOptions,
     bool allowSynchronousQueryExecution)
     : this(
         container,
         cosmosJsonSerializer,
         queryClient,
         cosmosQueryRequestOptions,
         null,
         allowSynchronousQueryExecution)
 {
 }
 public NetworkAttachedDocumentContainer(
     ContainerInternal container,
     CosmosQueryClient cosmosQueryClient,
     CosmosDiagnosticsContext diagnosticsContext,
     QueryRequestOptions queryRequestOptions = null,
     string resourceLink       = null,
     ResourceType resourceType = ResourceType.Document)
 {
     this.container           = container ?? throw new ArgumentNullException(nameof(container));
     this.cosmosQueryClient   = cosmosQueryClient ?? throw new ArgumentNullException(nameof(cosmosQueryClient));
     this.diagnosticsContext  = diagnosticsContext;
     this.queryRequestOptions = queryRequestOptions;
     this.resourceLink        = resourceLink ?? this.container.LinkUri;
     this.resourceType        = resourceType;
 }
示例#16
0
 public static CosmosQueryContext CreateContext(
     CosmosQueryClient cosmosQueryClient)
 {
     return(new CosmosQueryContextCore(
                client: cosmosQueryClient,
                queryRequestOptions: null,
                resourceTypeEnum: ResourceType.Document,
                operationType: OperationType.Query,
                resourceType: typeof(ToDoItem),
                resourceLink: DefaultResourceLink,
                correlatedActivityId: Guid.NewGuid(),
                isContinuationExpected: true,
                allowNonValueAggregateQuery: true,
                containerResourceId: DefaultCollectionRid));
 }
示例#17
0
 public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
     CosmosQueryClient cosmosQueryClient,
     string requestContinuation,
     Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
     IReadOnlyDictionary <string, AggregateOperator?> groupByAliasToAggregateType,
     IReadOnlyList <string> orderedAliases,
     bool hasSelectValue)
 {
     // We do not support continuation tokens for GROUP BY.
     return(new GroupByDocumentQueryExecutionComponent(
                cosmosQueryClient,
                groupByAliasToAggregateType,
                orderedAliases,
                hasSelectValue,
                await createSourceCallback(requestContinuation)));
 }
示例#18
0
        /// <summary>
        /// Initializes a new instance of the DistinctDocumentQueryExecutionComponent class.
        /// </summary>
        /// <param name="queryClient">The query client</param>
        /// <param name="distinctQueryType">The type of distinct query.</param>
        /// <param name="previousHash">The previous that distinct map saw.</param>
        /// <param name="source">The source to drain from.</param>
        private DistinctDocumentQueryExecutionComponent(
            CosmosQueryClient queryClient,
            DistinctQueryType distinctQueryType,
            UInt192?previousHash,
            IDocumentQueryExecutionComponent source)
            : base(source)
        {
            if (distinctQueryType == DistinctQueryType.None)
            {
                throw new ArgumentException("It doesn't make sense to create a distinct component of type None.");
            }

            this.queryClient       = queryClient;
            this.distinctQueryType = distinctQueryType;
            this.distinctMap       = DistinctMap.Create(distinctQueryType, previousHash);
        }
            public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
                CosmosQueryClient cosmosQueryClient,
                string requestContinuation,
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
                IReadOnlyDictionary <string, AggregateOperator?> groupByAliasToAggregateType,
                IReadOnlyList <string> orderedAliases,
                bool hasSelectValue)
            {
                GroupByContinuationToken groupByContinuationToken;

                if (requestContinuation != null)
                {
                    if (!GroupByContinuationToken.TryParse(requestContinuation, out groupByContinuationToken))
                    {
                        throw cosmosQueryClient.CreateBadRequestException(
                                  $"Invalid {nameof(GroupByContinuationToken)}: '{requestContinuation}'");
                    }
                }
                else
                {
                    groupByContinuationToken = new GroupByContinuationToken(
                        groupingTableContinuationToken: null,
                        sourceContinuationToken: null);
                }

                IDocumentQueryExecutionComponent source;

                if (groupByContinuationToken.SourceContinuationToken == ComputeGroupByDocumentQueryExecutionComponent.DoneReadingGroupingsContinuationToken)
                {
                    source = DoneDocumentQueryExecutionComponent.Value;
                }
                else
                {
                    source = await createSourceCallback(groupByContinuationToken.SourceContinuationToken);
                }

                GroupingTable groupingTable = GroupingTable.CreateFromContinuationToken(
                    cosmosQueryClient,
                    groupByAliasToAggregateType,
                    orderedAliases,
                    hasSelectValue,
                    groupByContinuationToken.GroupingTableContinuationToken);

                return(new ComputeGroupByDocumentQueryExecutionComponent(
                           source,
                           groupingTable));
            }
            public static GroupingTable CreateFromContinuationToken(CosmosQueryClient cosmosQueryClient,
                                                                    IReadOnlyDictionary <string, AggregateOperator?> groupByAliasToAggregateType,
                                                                    IReadOnlyList <string> orderedAliases,
                                                                    bool hasSelectValue,
                                                                    string groupingTableContinuationToken)
            {
                GroupingTable groupingTable = new GroupingTable(
                    cosmosQueryClient,
                    groupByAliasToAggregateType,
                    orderedAliases,
                    hasSelectValue);

                if (groupingTableContinuationToken != null)
                {
                    if (!CosmosElement.TryParse(
                            groupingTableContinuationToken,
                            out CosmosObject parsedGroupingTableContinuations))
                    {
                        throw cosmosQueryClient.CreateBadRequestException($"Invalid GroupingTableContinuationToken");
                    }

                    foreach (KeyValuePair <string, CosmosElement> kvp in parsedGroupingTableContinuations)
                    {
                        string        key   = kvp.Key;
                        CosmosElement value = kvp.Value;

                        UInt128 groupByKey = UInt128.Parse(key);

                        if (!(value is CosmosString singleGroupAggregatorContinuationToken))
                        {
                            throw cosmosQueryClient.CreateBadRequestException($"Invalid GroupingTableContinuationToken");
                        }

                        SingleGroupAggregator singleGroupAggregator = SingleGroupAggregator.Create(
                            cosmosQueryClient,
                            EmptyAggregateOperators,
                            groupByAliasToAggregateType,
                            orderedAliases,
                            hasSelectValue,
                            singleGroupAggregatorContinuationToken.Value);

                        groupingTable.table[groupByKey] = singleGroupAggregator;
                    }
                }

                return(groupingTable);
            }
示例#21
0
 public NetworkAttachedDocumentContainer(
     ContainerInternal container,
     CosmosQueryClient cosmosQueryClient,
     Guid correlatedActivityId,
     QueryRequestOptions queryRequestOptions           = null,
     ChangeFeedRequestOptions changeFeedRequestOptions = null,
     string resourceLink       = null,
     ResourceType resourceType = ResourceType.Document)
 {
     this.container                = container ?? throw new ArgumentNullException(nameof(container));
     this.cosmosQueryClient        = cosmosQueryClient ?? throw new ArgumentNullException(nameof(cosmosQueryClient));
     this.queryRequestOptions      = queryRequestOptions;
     this.changeFeedRequestOptions = changeFeedRequestOptions;
     this.resourceLink             = resourceLink ?? this.container.LinkUri;
     this.resourceType             = resourceType;
     this.correlatedActivityId     = correlatedActivityId;
 }
        /// <summary>
        /// Creates a AggregateDocumentQueryExecutionComponent.
        /// </summary>
        /// <param name="executionEnvironment">The environment to execute on.</param>
        /// <param name="queryClient">The query client.</param>
        /// <param name="aggregates">The aggregates.</param>
        /// <param name="aliasToAggregateType">The alias to aggregate type.</param>
        /// <param name="orderedAliases">The ordering of the aliases.</param>
        /// <param name="hasSelectValue">Whether or not the query has the 'VALUE' keyword.</param>
        /// <param name="requestContinuation">The continuation token to resume from.</param>
        /// <param name="createSourceCallback">The callback to create the source component that supplies the local aggregates.</param>
        /// <returns>The AggregateDocumentQueryExecutionComponent.</returns>
        public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
            ExecutionEnvironment executionEnvironment,
            CosmosQueryClient queryClient,
            AggregateOperator[] aggregates,
            IReadOnlyDictionary <string, AggregateOperator?> aliasToAggregateType,
            IReadOnlyList <string> orderedAliases,
            bool hasSelectValue,
            string requestContinuation,
            Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback)
        {
            IDocumentQueryExecutionComponent aggregateDocumentQueryExecutionComponent;

            switch (executionEnvironment)
            {
            case ExecutionEnvironment.Client:
                aggregateDocumentQueryExecutionComponent = await ClientAggregateDocumentQueryExecutionComponent.CreateAsync(
                    queryClient,
                    aggregates,
                    aliasToAggregateType,
                    orderedAliases,
                    hasSelectValue,
                    requestContinuation,
                    createSourceCallback);

                break;

            case ExecutionEnvironment.Compute:
                aggregateDocumentQueryExecutionComponent = await ComputeAggregateDocumentQueryExecutionComponent.CreateAsync(
                    queryClient,
                    aggregates,
                    aliasToAggregateType,
                    orderedAliases,
                    hasSelectValue,
                    requestContinuation,
                    createSourceCallback);

                break;

            default:
                throw new ArgumentException($"Unknown {nameof(ExecutionEnvironment)}: {executionEnvironment}.");
            }

            return(aggregateDocumentQueryExecutionComponent);
        }
示例#23
0
            public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
                CosmosQueryClient queryClient,
                AggregateOperator[] aggregates,
                IReadOnlyDictionary <string, AggregateOperator?> aliasToAggregateType,
                IReadOnlyList <string> orderedAliases,
                bool hasSelectValue,
                string requestContinuation,
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback)
            {
                string sourceContinuationToken;
                string singleGroupAggregatorContinuationToken;

                if (requestContinuation != null)
                {
                    if (!AggregateContinuationToken.TryParse(requestContinuation, out AggregateContinuationToken aggregateContinuationToken))
                    {
                        throw queryClient.CreateBadRequestException($"Malfomed {nameof(AggregateContinuationToken)}: '{requestContinuation}'");
                    }

                    sourceContinuationToken = aggregateContinuationToken.SourceContinuationToken;
                    singleGroupAggregatorContinuationToken = aggregateContinuationToken.SingleGroupAggregatorContinuationToken;
                }
                else
                {
                    sourceContinuationToken = null;
                    singleGroupAggregatorContinuationToken = null;
                }

                IDocumentQueryExecutionComponent source = await createSourceCallback(sourceContinuationToken);

                SingleGroupAggregator singleGroupAggregator = SingleGroupAggregator.Create(
                    queryClient,
                    aggregates,
                    aliasToAggregateType,
                    orderedAliases,
                    hasSelectValue,
                    singleGroupAggregatorContinuationToken);

                return(new ComputeAggregateDocumentQueryExecutionComponent(
                           source,
                           singleGroupAggregator,
                           hasSelectValue));
            }
示例#24
0
        public static async Task <PartitionedQueryExecutionInfo> GetQueryPlanWithServiceInteropAsync(
            CosmosQueryClient queryClient,
            SqlQuerySpec sqlQuerySpec,
            PartitionKeyDefinition partitionKeyDefinition,
            bool hasLogicalPartitionKey,
            CancellationToken cancellationToken = default)
        {
            if (queryClient == null)
            {
                throw new ArgumentNullException(nameof(queryClient));
            }

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

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

            cancellationToken.ThrowIfCancellationRequested();
            QueryPlanHandler queryPlanHandler = new QueryPlanHandler(queryClient);

            TryCatch <PartitionedQueryExecutionInfo> tryGetQueryPlan = await queryPlanHandler.TryGetQueryPlanAsync(
                sqlQuerySpec,
                partitionKeyDefinition,
                QueryPlanRetriever.SupportedQueryFeatures,
                hasLogicalPartitionKey,
                cancellationToken);

            if (!tryGetQueryPlan.Succeeded)
            {
                throw new CosmosException(
                          System.Net.HttpStatusCode.BadRequest,
                          tryGetQueryPlan.Exception.ToString());
            }

            return(tryGetQueryPlan.Result);
        }
            public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
                CosmosQueryClient cosmosQueryClient,
                string requestContinuation,
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
                IReadOnlyDictionary <string, AggregateOperator?> groupByAliasToAggregateType,
                IReadOnlyList <string> orderedAliases,
                bool hasSelectValue)
            {
                IDocumentQueryExecutionComponent source = await createSourceCallback(requestContinuation);

                GroupingTable groupingTable = GroupingTable.CreateFromContinuationToken(
                    cosmosQueryClient,
                    groupByAliasToAggregateType,
                    orderedAliases,
                    hasSelectValue,
                    groupingTableContinuationToken: null);

                return(new ClientGroupByDocumentQueryExecutionComponent(
                           source,
                           groupingTable));
            }
示例#26
0
 public CosmosLinqQuery(
     CosmosContainerCore container,
     CosmosJsonSerializer cosmosJsonSerializer,
     CosmosQueryClient queryClient,
     QueryRequestOptions cosmosQueryRequestOptions,
     Expression expression,
     bool allowSynchronousQueryExecution)
 {
     this.container                      = container ?? throw new ArgumentNullException(nameof(container));
     this.cosmosJsonSerializer           = cosmosJsonSerializer;
     this.queryClient                    = queryClient;
     this.cosmosQueryRequestOptions      = cosmosQueryRequestOptions;
     this.expression                     = expression ?? Expression.Constant(this);
     this.allowSynchronousQueryExecution = allowSynchronousQueryExecution;
     this.queryProvider                  = new CosmosLinqQueryProvider(
         container,
         cosmosJsonSerializer,
         queryClient,
         cosmosQueryRequestOptions,
         this.allowSynchronousQueryExecution);
     this.correlatedActivityId = Guid.NewGuid();
 }
示例#27
0
        /// <summary>
        /// Creates an DistinctDocumentQueryExecutionComponent
        /// </summary>
        /// <param name="queryClient">The query client</param>
        /// <param name="requestContinuation">The continuation token.</param>
        /// <param name="createSourceCallback">The callback to create the source to drain from.</param>
        /// <param name="distinctQueryType">The type of distinct query.</param>
        /// <returns>A task to await on and in return </returns>
        public static async Task <DistinctDocumentQueryExecutionComponent> CreateAsync(
            CosmosQueryClient queryClient,
            string requestContinuation,
            Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
            DistinctQueryType distinctQueryType)
        {
            DistinctContinuationToken distinctContinuationToken = new DistinctContinuationToken(null, null);

            if (requestContinuation != null)
            {
                distinctContinuationToken = DistinctContinuationToken.Parse(queryClient, requestContinuation);
                if (distinctQueryType != DistinctQueryType.Ordered && distinctContinuationToken.LastHash != null)
                {
                    throw queryClient.CreateBadRequestException($"DistinctContinuationToken is malformed: {distinctContinuationToken}. DistinctContinuationToken can not have a 'lastHash', when the query type is not ordered (ex SELECT DISTINCT VALUE c.blah FROM c ORDER BY c.blah).");
                }
            }

            return(new DistinctDocumentQueryExecutionComponent(
                       queryClient,
                       distinctQueryType,
                       distinctContinuationToken.LastHash,
                       await createSourceCallback(distinctContinuationToken.SourceToken)));
        }
            public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
                CosmosQueryClient queryClient,
                AggregateOperator[] aggregates,
                IReadOnlyDictionary <string, AggregateOperator?> aliasToAggregateType,
                IReadOnlyList <string> orderedAliases,
                bool hasSelectValue,
                string requestContinuation,
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback)
            {
                IDocumentQueryExecutionComponent source = await createSourceCallback(requestContinuation);

                SingleGroupAggregator singleGroupAggregator = SingleGroupAggregator.Create(
                    queryClient,
                    aggregates,
                    aliasToAggregateType,
                    orderedAliases,
                    hasSelectValue,
                    continuationToken: null);

                return(new ClientAggregateDocumentQueryExecutionComponent(
                           source,
                           singleGroupAggregator,
                           hasSelectValue));
            }
示例#29
0
        /// <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="testSettings">Test flags.</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,
            Documents.PartitionKeyRange partitionKeyRange,
            ProduceAsyncCompleteDelegate produceAsyncCompleteCallback,
            IComparer <ItemProducerTree> itemProducerTreeComparer,
            IEqualityComparer <CosmosElement> equalityComparer,
            TestInjections testSettings,
            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,
                (itemsBuffered, resourceUnitUsage, diagnostics, requestLength, token) => produceAsyncCompleteCallback(this, itemsBuffered, resourceUnitUsage, diagnostics, requestLength, token),
                equalityComparer,
                testSettings,
                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,
                testSettings,
                deferFirstPage,
                collectionRid,
                initialPageSize);
            this.executeWithSplitProofingSemaphore = new SemaphoreSlim(1, 1);
        }
示例#30
0
        private static async Task <TryCatch <CosmosQueryExecutionContext> > TryCreateCoreContextAsync(
            CosmosQueryContext cosmosQueryContext,
            InputParameters inputParameters,
            CancellationToken cancellationToken)
        {
            // The default
            using (cosmosQueryContext.CreateDiagnosticScope("CreateQueryPipeline"))
            {
                // Try to parse the continuation token.
                CosmosElement continuationToken = inputParameters.InitialUserContinuationToken;
                PartitionedQueryExecutionInfo queryPlanFromContinuationToken = inputParameters.PartitionedQueryExecutionInfo;
                if (continuationToken != null)
                {
                    if (!PipelineContinuationToken.TryCreateFromCosmosElement(
                            continuationToken,
                            out PipelineContinuationToken pipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Malformed {nameof(PipelineContinuationToken)}: {continuationToken}.")));
                    }

                    if (PipelineContinuationToken.IsTokenFromTheFuture(pipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(PipelineContinuationToken)} Continuation token is from a newer version of the SDK. " +
                                       $"Upgrade the SDK to avoid this issue." +
                                       $"{continuationToken}.")));
                    }

                    if (!PipelineContinuationToken.TryConvertToLatest(
                            pipelineContinuationToken,
                            out PipelineContinuationTokenV1_1 latestVersionPipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(PipelineContinuationToken)}: '{continuationToken}' is no longer supported.")));
                    }

                    continuationToken = latestVersionPipelineContinuationToken.SourceContinuationToken;
                    if (latestVersionPipelineContinuationToken.QueryPlan != null)
                    {
                        queryPlanFromContinuationToken = latestVersionPipelineContinuationToken.QueryPlan;
                    }
                }

                CosmosQueryClient        cosmosQueryClient        = cosmosQueryContext.QueryClient;
                ContainerQueryProperties containerQueryProperties = await cosmosQueryClient.GetCachedContainerQueryPropertiesAsync(
                    cosmosQueryContext.ResourceLink,
                    inputParameters.PartitionKey,
                    cancellationToken);

                cosmosQueryContext.ContainerResourceId = containerQueryProperties.ResourceId;

                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo;
                if (inputParameters.ForcePassthrough)
                {
                    partitionedQueryExecutionInfo = new PartitionedQueryExecutionInfo()
                    {
                        QueryInfo = new QueryInfo()
                        {
                            Aggregates     = null,
                            DistinctType   = DistinctQueryType.None,
                            GroupByAliases = null,
                            GroupByAliasToAggregateType = null,
                            GroupByExpressions          = null,
                            HasSelectValue     = false,
                            Limit              = null,
                            Offset             = null,
                            OrderBy            = null,
                            OrderByExpressions = null,
                            RewrittenQuery     = null,
                            Top = null,
                        },
                        QueryRanges = new List <Documents.Routing.Range <string> >(),
                    };
                }
                else if (queryPlanFromContinuationToken != null)
                {
                    partitionedQueryExecutionInfo = queryPlanFromContinuationToken;
                }
                else
                {
                    // If the query would go to gateway, but we have a partition key,
                    // then try seeing if we can execute as a passthrough using client side only logic.
                    // This is to short circuit the need to go to the gateway to get the query plan.
                    if (cosmosQueryContext.QueryClient.ByPassQueryParsing() &&
                        inputParameters.PartitionKey.HasValue)
                    {
                        bool     parsed;
                        SqlQuery sqlQuery;
                        using (cosmosQueryContext.CreateDiagnosticScope("QueryParsing"))
                        {
                            parsed = SqlQuery.TryParse(inputParameters.SqlQuerySpec.QueryText, out sqlQuery);
                        }

                        if (parsed)
                        {
                            bool hasDistinct            = sqlQuery.SelectClause.HasDistinct;
                            bool hasGroupBy             = sqlQuery.GroupByClause != default;
                            bool hasAggregates          = AggregateProjectionDetector.HasAggregate(sqlQuery.SelectClause.SelectSpec);
                            bool createPassthroughQuery = !hasAggregates && !hasDistinct && !hasGroupBy;

                            if (createPassthroughQuery)
                            {
                                TestInjections.ResponseStats responseStats = inputParameters?.TestInjections?.Stats;
                                if (responseStats != null)
                                {
                                    responseStats.PipelineType = TestInjections.PipelineType.Passthrough;
                                }

                                // Only thing that matters is that we target the correct range.
                                Documents.PartitionKeyDefinition   partitionKeyDefinition = GetPartitionKeyDefinition(inputParameters, containerQueryProperties);
                                List <Documents.PartitionKeyRange> targetRanges           = await cosmosQueryContext.QueryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                                    cosmosQueryContext.ResourceLink,
                                    containerQueryProperties.ResourceId,
                                    inputParameters.PartitionKey.Value.InternalKey.GetEffectivePartitionKeyString(partitionKeyDefinition));

                                return(await CosmosQueryExecutionContextFactory.TryCreatePassthroughQueryExecutionContextAsync(
                                           cosmosQueryContext,
                                           inputParameters,
                                           partitionedQueryExecutionInfo : new PartitionedQueryExecutionInfo(),
                                           targetRanges,
                                           containerQueryProperties.ResourceId,
                                           cancellationToken));
                            }
                        }
                    }

                    if (cosmosQueryContext.QueryClient.ByPassQueryParsing())
                    {
                        // 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(
                            cosmosQueryContext,
                            inputParameters.SqlQuerySpec,
                            cosmosQueryContext.ResourceLink,
                            inputParameters.PartitionKey,
                            cancellationToken);
                    }
                    else
                    {
                        using (cosmosQueryContext.CreateDiagnosticScope("ServiceInterop"))
                        {
                            Documents.PartitionKeyDefinition partitionKeyDefinition = GetPartitionKeyDefinition(inputParameters, containerQueryProperties);

                            partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanWithServiceInteropAsync(
                                cosmosQueryContext.QueryClient,
                                inputParameters.SqlQuerySpec,
                                partitionKeyDefinition,
                                inputParameters.PartitionKey != null,
                                cancellationToken);
                        }
                    }
                }

                return(await TryCreateFromPartitionedQuerExecutionInfoAsync(
                           partitionedQueryExecutionInfo,
                           containerQueryProperties,
                           cosmosQueryContext,
                           inputParameters,
                           cancellationToken));
            }
        }