public async Task <PartitionedQueryExecutionInfo> GetPartitionedQueryExecutionInfoAsync( PartitionKeyDefinition partitionKeyDefinition, bool requireFormattableOrderByQuery, bool isContinuationExpected, bool allowNonValueAggregateQuery, bool hasLogicalPartitionKey, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // $ISSUE-felixfan-2016-07-13: We should probably get PartitionedQueryExecutionInfo from Gateway in GatewayMode QueryPartitionProvider queryPartitionProvider = await this.Client.GetQueryPartitionProviderAsync(cancellationToken); TryCatch <PartitionedQueryExecutionInfo> tryGetPartitionedQueryExecutionInfo = queryPartitionProvider.TryGetPartitionedQueryExecutionInfo( this.QuerySpec, partitionKeyDefinition, requireFormattableOrderByQuery, isContinuationExpected, allowNonValueAggregateQuery, hasLogicalPartitionKey); if (!tryGetPartitionedQueryExecutionInfo.Succeeded) { throw new BadRequestException(tryGetPartitionedQueryExecutionInfo.Exception); } return(tryGetPartitionedQueryExecutionInfo.Result); }
public async Task <PartitionedQueryExecutionInfo> GetPartitionedQueryExecutionInfoAsync( PartitionKeyDefinition partitionKeyDefinition, bool requireFormattableOrderByQuery, bool isContinuationExpected, CancellationToken cancellationToken) { // $ISSUE-felixfan-2016-07-13: We should probably get PartitionedQueryExecutionInfo from Gateway in GatewayMode QueryPartitionProvider queryPartitionProvider = await this.client.GetQueryPartitionProviderAsync(cancellationToken); return(queryPartitionProvider.GetPartitionedQueryExecutionInfo(this.QuerySpec, partitionKeyDefinition, requireFormattableOrderByQuery, isContinuationExpected)); }
public async Task <QueryPartitionProvider> GetQueryPartitionProviderAsync(CancellationToken cancellationToken) { if (this.queryPartitionProvider == null) { await this.semaphore.WaitAsync(cancellationToken); if (this.queryPartitionProvider == null) { cancellationToken.ThrowIfCancellationRequested(); this.queryPartitionProvider = new QueryPartitionProvider(await this.innerClient.GetQueryEngineConfiguration()); } this.semaphore.Release(); } return(this.queryPartitionProvider); }
public static async Task <PartitionedQueryExecutionInfo> GetPartitionedQueryExecutionInfoAsync( CosmosQueryClient queryClient, SqlQuerySpec sqlQuerySpec, PartitionKeyDefinition partitionKeyDefinition, bool requireFormattableOrderByQuery, bool isContinuationExpected, bool allowNonValueAggregateQuery, CancellationToken cancellationToken) { // $ISSUE-felixfan-2016-07-13: We should probably get PartitionedQueryExecutionInfo from Gateway in GatewayMode QueryPartitionProvider queryPartitionProvider = await queryClient.GetQueryPartitionProviderAsync(cancellationToken); return(queryPartitionProvider.GetPartitionedQueryExecutionInfo(sqlQuerySpec, partitionKeyDefinition, requireFormattableOrderByQuery, isContinuationExpected, allowNonValueAggregateQuery)); }
public async Task <PartitionedQueryExecutionInfo> GetPartitionedQueryExecutionInfoAsync( PartitionKeyDefinition partitionKeyDefinition, bool requireFormattableOrderByQuery, bool isContinuationExpected, bool allowNonValueAggregateQuery, bool hasLogicalPartitionKey, CancellationToken cancellationToken) { // $ISSUE-felixfan-2016-07-13: We should probably get PartitionedQueryExecutionInfo from Gateway in GatewayMode QueryPartitionProvider queryPartitionProvider = await this.client.GetQueryPartitionProviderAsync(cancellationToken); return(queryPartitionProvider.GetPartitionedQueryExecutionInfo( (errorMessage) => new BadRequestException(errorMessage), this.QuerySpec, partitionKeyDefinition, requireFormattableOrderByQuery, isContinuationExpected, allowNonValueAggregateQuery, hasLogicalPartitionKey)); }
private async Task <Tuple <PartitionRoutingHelper.ResolvedRangeInfo, IReadOnlyList <Range <string> > > > TryGetTargetPartitionKeyRangeAsync( DocumentServiceRequest request, ContainerProperties collection, QueryPartitionProvider queryPartitionProvider, IRoutingMapProvider routingMapProvider, Range <string> rangeFromContinuationToken, List <CompositeContinuationToken> suppliedTokens) { string version = request.Headers[HttpConstants.HttpHeaders.Version]; version = string.IsNullOrEmpty(version) ? HttpConstants.Versions.CurrentVersion : version; bool enableCrossPartitionQuery = false; string enableCrossPartitionQueryHeader = request.Headers[HttpConstants.HttpHeaders.EnableCrossPartitionQuery]; if (enableCrossPartitionQueryHeader != null) { if (!bool.TryParse(enableCrossPartitionQueryHeader, out enableCrossPartitionQuery)) { throw new BadRequestException( string.Format( CultureInfo.InvariantCulture, RMResources.InvalidHeaderValue, enableCrossPartitionQueryHeader, HttpConstants.HttpHeaders.EnableCrossPartitionQuery)); } } IReadOnlyList <Range <string> > providedRanges; if (!this.providedRangesCache.TryGetValue(collection.ResourceId, out providedRanges)) { if (this.ShouldExecuteQueryRequest) { FeedOptions feedOptions = this.GetFeedOptions(null); PartitionKeyDefinition partitionKeyDefinition; if ((feedOptions.Properties != null) && feedOptions.Properties.TryGetValue( DefaultDocumentQueryExecutionContext.InternalPartitionKeyDefinitionProperty, out object partitionKeyDefinitionObject)) { if (partitionKeyDefinitionObject is PartitionKeyDefinition definition) { partitionKeyDefinition = definition; } else { throw new ArgumentException( "partitionkeydefinition has invalid type", nameof(partitionKeyDefinitionObject)); } } else { partitionKeyDefinition = collection.PartitionKey; } providedRanges = PartitionRoutingHelper.GetProvidedPartitionKeyRanges( (errorMessage) => new BadRequestException(errorMessage), this.QuerySpec, enableCrossPartitionQuery, false, this.isContinuationExpected, false, //haslogicalpartitionkey partitionKeyDefinition, queryPartitionProvider, version, out QueryInfo queryInfo); } else if (request.Properties != null && request.Properties.TryGetValue( WFConstants.BackendHeaders.EffectivePartitionKeyString, out object effectivePartitionKey)) { if (effectivePartitionKey is string effectivePartitionKeyString) { providedRanges = new List <Range <string> >() { Range <string> .GetPointRange(effectivePartitionKeyString), }; } else { throw new ArgumentException( "EffectivePartitionKey must be a string", WFConstants.BackendHeaders.EffectivePartitionKeyString); } } else { providedRanges = new List <Range <string> > { new Range <string>( PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, true, false) }; } this.providedRangesCache[collection.ResourceId] = providedRanges; } PartitionRoutingHelper.ResolvedRangeInfo resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRangeAsync( providedRanges, routingMapProvider, collection.ResourceId, rangeFromContinuationToken, suppliedTokens); if (resolvedRangeInfo.ResolvedRange == null) { return(null); } else { return(Tuple.Create(resolvedRangeInfo, providedRanges)); } }
private async Task <Tuple <DocumentFeedResponse <CosmosElement>, string> > ExecuteOnceAsync( IDocumentClientRetryPolicy retryPolicyInstance, CancellationToken cancellationToken) { // Don't reuse request, as the rest of client SDK doesn't reuse requests between retries. // The code leaves some temporary garbage in request (in RequestContext etc.), // which shold be erased during retries. using (DocumentServiceRequest request = await this.CreateRequestAsync()) { DocumentFeedResponse <CosmosElement> feedRespose; string partitionIdentifier; // We need to determine how to execute the request: if (LogicalPartitionKeyProvided(request)) { feedRespose = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); partitionIdentifier = $"PKId({request.Headers[HttpConstants.HttpHeaders.PartitionKey]})"; } else if (PhysicalPartitionKeyRangeIdProvided(this)) { CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); ContainerProperties collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None); request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, base.PartitionKeyRangeId)); feedRespose = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); partitionIdentifier = base.PartitionKeyRangeId; } else { // The query is going to become a full fan out, but we go one partition at a time. if (ServiceInteropAvailable()) { // Get the routing map provider CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); ContainerProperties collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None); QueryPartitionProvider queryPartitionProvider = await this.Client.GetQueryPartitionProviderAsync(cancellationToken); IRoutingMapProvider routingMapProvider = await this.Client.GetRoutingMapProviderAsync(); // Figure out what partition you are going to based on the range from the continuation token // If token is null then just start at partitionKeyRangeId "0" List <CompositeContinuationToken> suppliedTokens; Range <string> rangeFromContinuationToken = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken( request.Headers, out suppliedTokens); Tuple <PartitionRoutingHelper.ResolvedRangeInfo, IReadOnlyList <Range <string> > > queryRoutingInfo = await this.TryGetTargetPartitionKeyRangeAsync( request, collection, queryPartitionProvider, routingMapProvider, rangeFromContinuationToken, suppliedTokens); if (request.IsNameBased && queryRoutingInfo == null) { request.ForceNameCacheRefresh = true; collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None); queryRoutingInfo = await this.TryGetTargetPartitionKeyRangeAsync( request, collection, queryPartitionProvider, routingMapProvider, rangeFromContinuationToken, suppliedTokens); } if (queryRoutingInfo == null) { throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Was not able to get queryRoutingInfo even after resolve collection async with force name cache refresh to the following collectionRid: {collection.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}"); } request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, queryRoutingInfo.Item1.ResolvedRange.Id)); DocumentFeedResponse <CosmosElement> response = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); // Form a composite continuation token (range + backend continuation token). // If the backend continuation token was null for the range, // then use the next adjacent range. // This is how the default execution context serially visits every partition. if (!await this.partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync( response.Headers, providedPartitionKeyRanges: queryRoutingInfo.Item2, routingMapProvider: routingMapProvider, collectionRid: collection.ResourceId, resolvedRangeInfo: queryRoutingInfo.Item1)) { // Collection to which this request was resolved doesn't exist. // Retry policy will refresh the cache and return NotFound. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Call to TryAddPartitionKeyRangeToContinuationTokenAsync failed to the following collectionRid: {collection.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}"); } feedRespose = response; partitionIdentifier = queryRoutingInfo.Item1.ResolvedRange.Id; } else { // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop for parsing the query, // so forcing the request through Gateway. We are also now by-passing this for 32-bit host process in NETFX on Windows // as the ServiceInterop dll is only available in 64-bit. request.UseGatewayMode = true; feedRespose = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); partitionIdentifier = "Gateway"; } } return(new Tuple <DocumentFeedResponse <CosmosElement>, string>(feedRespose, partitionIdentifier)); } }
private async Task <Tuple <PartitionRoutingHelper.ResolvedRangeInfo, IReadOnlyList <Range <string> > > > TryGetTargetPartitionKeyRangeAsync( DocumentServiceRequest request, CosmosContainerSettings collection, QueryPartitionProvider queryPartitionProvider, IRoutingMapProvider routingMapProvider, Range <string> rangeFromContinuationToken, List <CompositeContinuationToken> suppliedTokens) { string version = request.Headers[HttpConstants.HttpHeaders.Version]; version = string.IsNullOrEmpty(version) ? HttpConstants.Versions.CurrentVersion : version; bool enableCrossPartitionQuery = false; string enableCrossPartitionQueryHeader = request.Headers[HttpConstants.HttpHeaders.EnableCrossPartitionQuery]; if (enableCrossPartitionQueryHeader != null) { if (!bool.TryParse(enableCrossPartitionQueryHeader, out enableCrossPartitionQuery)) { throw new BadRequestException( string.Format( CultureInfo.InvariantCulture, RMResources.InvalidHeaderValue, enableCrossPartitionQueryHeader, HttpConstants.HttpHeaders.EnableCrossPartitionQuery)); } } IReadOnlyList <Range <string> > providedRanges; if (!this.providedRangesCache.TryGetValue(collection.ResourceId, out providedRanges)) { if (this.ShouldExecuteQueryRequest) { QueryInfo queryInfo; providedRanges = PartitionRoutingHelper.GetProvidedPartitionKeyRanges( this.QuerySpec, enableCrossPartitionQuery, false, isContinuationExpected, collection.PartitionKey, queryPartitionProvider, version, out queryInfo); } else { providedRanges = new List <Range <string> > { new Range <string>( PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, true, false) }; } this.providedRangesCache[collection.ResourceId] = providedRanges; } PartitionRoutingHelper.ResolvedRangeInfo resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRange( providedRanges, routingMapProvider, collection.ResourceId, rangeFromContinuationToken, suppliedTokens); if (resolvedRangeInfo.ResolvedRange == null) { return(null); } else { return(Tuple.Create(resolvedRangeInfo, providedRanges)); } }
private async Task <FeedResponse <dynamic> > ExecuteOnceAsync(IDocumentClientRetryPolicy retryPolicyInstance, CancellationToken cancellationToken) { // Don't reuse request, as the rest of client SDK doesn't reuse requests between retries. // The code leaves some temporary garbage in request (in RequestContext etc.), // which shold be erased during retries. using (DocumentServiceRequest request = await this.CreateRequestAsync()) { if (retryPolicyInstance != null) { retryPolicyInstance.OnBeforeSendRequest(request); } if (!string.IsNullOrEmpty(request.Headers[HttpConstants.HttpHeaders.PartitionKey]) || !request.ResourceType.IsPartitioned()) { return(await this.ExecuteRequestAsync(request, cancellationToken)); } CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); CosmosContainerSettings collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None); if (!string.IsNullOrEmpty(base.PartitionKeyRangeId)) { request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, base.PartitionKeyRangeId)); return(await this.ExecuteRequestAsync(request, cancellationToken)); } // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop for parsing the query, // so forcing the request through Gateway. We are also now by-passing this for 32-bit host process in NETFX on Windows // as the ServiceInterop dll is only available in 64-bit. if (CustomTypeExtensions.ByPassQueryParsing()) { request.UseGatewayMode = true; return(await this.ExecuteRequestAsync(request, cancellationToken)); } QueryPartitionProvider queryPartitionProvider = await this.Client.GetQueryPartitionProviderAsync(cancellationToken); IRoutingMapProvider routingMapProvider = await this.Client.GetRoutingMapProviderAsync(); List <CompositeContinuationToken> suppliedTokens; Range <string> rangeFromContinuationToken = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken(request.Headers, out suppliedTokens); Tuple <PartitionRoutingHelper.ResolvedRangeInfo, IReadOnlyList <Range <string> > > queryRoutingInfo = await this.TryGetTargetPartitionKeyRangeAsync( request, collection, queryPartitionProvider, routingMapProvider, rangeFromContinuationToken, suppliedTokens); if (request.IsNameBased && queryRoutingInfo == null) { request.ForceNameCacheRefresh = true; collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None); queryRoutingInfo = await this.TryGetTargetPartitionKeyRangeAsync( request, collection, queryPartitionProvider, routingMapProvider, rangeFromContinuationToken, suppliedTokens); } if (queryRoutingInfo == null) { throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Was not able to get queryRoutingInfo even after resolve collection async with force name cache refresh to the following collectionRid: {collection.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}"); } request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, queryRoutingInfo.Item1.ResolvedRange.Id)); FeedResponse <dynamic> response = await this.ExecuteRequestAsync(request, cancellationToken); if (!await this.partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync( response.Headers, providedPartitionKeyRanges: queryRoutingInfo.Item2, routingMapProvider: routingMapProvider, collectionRid: collection.ResourceId, resolvedRangeInfo: queryRoutingInfo.Item1)) { // Collection to which this request was resolved doesn't exist. // Retry policy will refresh the cache and return NotFound. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Call to TryAddPartitionKeyRangeToContinuationTokenAsync failed to the following collectionRid: {collection.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}"); } return(response); } }