public async Task TestGetPartitionRoutingInfo() { using (Stream stream = new MemoryStream(Properties.Resources.BaselineTest_PartitionRoutingHelper_GetPartitionRoutingInfo)) { using (StreamReader reader = new StreamReader(stream)) { GetPartitionRoutingInfoTestData testData = JsonConvert.DeserializeObject <GetPartitionRoutingInfoTestData>(reader.ReadToEnd()); CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( testData.RoutingMap.Select(range => Tuple.Create(range, (ServiceIdentity)null)), string.Empty); foreach (GetPartitionRoutingInfoTestCase testCase in testData.TestCases) { List <string> actualPartitionKeyRangeIds = new List <string>(); Range <string> startRange = Range <string> .GetEmptyRange(PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey); for (Range <string> currentRange = startRange; currentRange != null;) { RoutingMapProvider routingMapProvider = new RoutingMapProvider(routingMap); PartitionRoutingHelper.ResolvedRangeInfo resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRangeAsync(testCase.ProvidedRanges, routingMapProvider, string.Empty, currentRange, null, NoOpTrace.Singleton); actualPartitionKeyRangeIds.Add(resolvedRangeInfo.ResolvedRange.Id); INameValueCollection headers = new StoreRequestNameValueCollection(); await this.partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync(headers, testCase.ProvidedRanges, routingMapProvider, string.Empty, resolvedRangeInfo, NoOpTrace.Singleton); List <CompositeContinuationToken> suppliedTokens; Range <string> nextRange = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken(headers, out suppliedTokens); currentRange = nextRange.IsEmpty ? null : nextRange; } Assert.AreEqual(string.Join(", ", testCase.RoutingRangeIds), string.Join(", ", actualPartitionKeyRangeIds)); } } } }
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 <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)); } }