private async Task <ResolutionResult> TryResolveServerPartitionByPartitionKeyRangeIdAsync( DocumentServiceRequest request, ContainerProperties collection, CollectionRoutingMap routingMap, bool collectionCacheIsUpToDate, bool routingMapCacheIsUpToDate, bool forceRefreshPartitionAddresses, CancellationToken cancellationToken) { PartitionKeyRange partitionKeyRange = routingMap.TryGetRangeByPartitionKeyRangeId(request.PartitionKeyRangeIdentity.PartitionKeyRangeId); if (partitionKeyRange == null) { DefaultTrace.TraceInformation("Cannot resolve range '{0}'", request.PartitionKeyRangeIdentity.ToHeader()); return(this.HandleRangeAddressResolutionFailure(request, collectionCacheIsUpToDate, routingMapCacheIsUpToDate, routingMap)); } ServiceIdentity identity = routingMap.TryGetInfoByPartitionKeyRangeId(request.PartitionKeyRangeIdentity.PartitionKeyRangeId); PartitionAddressInformation addresses = await this.addressCache.TryGetAddressesAsync( request, new PartitionKeyRangeIdentity(collection.ResourceId, request.PartitionKeyRangeIdentity.PartitionKeyRangeId), identity, forceRefreshPartitionAddresses, cancellationToken); if (addresses == null) { DefaultTrace.TraceInformation("Cannot resolve addresses for range '{0}'", request.PartitionKeyRangeIdentity.ToHeader()); return(this.HandleRangeAddressResolutionFailure(request, collectionCacheIsUpToDate, routingMapCacheIsUpToDate, routingMap)); } return(new ResolutionResult(partitionKeyRange, addresses, identity)); }
private async Task <ResolutionResult> TryResolveServerPartitionAsync( DocumentServiceRequest request, ContainerProperties collection, CollectionRoutingMap routingMap, bool collectionCacheIsUptodate, bool collectionRoutingMapCacheIsUptodate, bool forceRefreshPartitionAddresses, CancellationToken cancellationToken) { // Check if this request partitionkeyrange-aware routing logic. We cannot retry here in this case // and need to bubble up errors. if (request.PartitionKeyRangeIdentity != null) { return(await this.TryResolveServerPartitionByPartitionKeyRangeIdAsync( request, collection, routingMap, collectionCacheIsUptodate, collectionRoutingMapCacheIsUptodate, forceRefreshPartitionAddresses, cancellationToken)); } if (!request.ResourceType.IsPartitioned() && !(request.ResourceType == ResourceType.StoredProcedure && request.OperationType == OperationType.ExecuteJavaScript) && // Collection head is sent internally for strong consistency given routing hints from original requst, which is for partitioned resource. !(request.ResourceType == ResourceType.Collection && request.OperationType == OperationType.Head)) { DefaultTrace.TraceCritical( "Shouldn't come here for non partitioned resources. resourceType : {0}, operationtype:{1}, resourceaddress:{2}", request.ResourceType, request.OperationType, request.ResourceAddress); throw new InternalServerErrorException(RMResources.InternalServerError) { ResourceAddress = request.ResourceAddress }; } PartitionKeyRange range; string partitionKeyString = request.Headers[HttpConstants.HttpHeaders.PartitionKey]; object effectivePartitionKeyStringObject = null; if (partitionKeyString != null) { range = this.TryResolveServerPartitionByPartitionKey( request, partitionKeyString, collectionCacheIsUptodate, collection, routingMap); } else if (request.Properties != null && request.Properties.TryGetValue( WFConstants.BackendHeaders.EffectivePartitionKeyString, out effectivePartitionKeyStringObject)) { // Allow EPK only for partitioned collection (excluding migrated fixed collections) if (!collection.HasPartitionKey || collection.PartitionKey.IsSystemKey.GetValueOrDefault(false)) { throw new ArgumentOutOfRangeException(nameof(collection)); } string effectivePartitionKeyString = effectivePartitionKeyStringObject as string; if (string.IsNullOrEmpty(effectivePartitionKeyString)) { throw new ArgumentOutOfRangeException(nameof(effectivePartitionKeyString)); } range = routingMap.GetRangeByEffectivePartitionKey(effectivePartitionKeyString); } else { range = this.TryResolveSinglePartitionCollection(request, routingMap, collectionCacheIsUptodate); } if (range == null) { // Collection cache or routing map cache is potentially outdated. Return null - // upper logic will refresh cache and retry. return(null); } ServiceIdentity serviceIdentity = routingMap.TryGetInfoByPartitionKeyRangeId(range.Id); PartitionAddressInformation addresses = await this.addressCache.TryGetAddressesAsync( request, new PartitionKeyRangeIdentity(collection.ResourceId, range.Id), serviceIdentity, forceRefreshPartitionAddresses, cancellationToken); if (addresses == null) { DefaultTrace.TraceVerbose( "Could not resolve addresses for identity {0}/{1}. Potentially collection cache or routing map cache is outdated. Return null - upper logic will refresh and retry. ", new PartitionKeyRangeIdentity(collection.ResourceId, range.Id), serviceIdentity); return(null); } return(new ResolutionResult(range, addresses, serviceIdentity)); }
public void TestCollectionRoutingMap() { ServiceIdentity serviceIdentity0 = new ServiceIdentity("1", new Uri("http://1"), false); ServiceIdentity serviceIdentity1 = new ServiceIdentity("2", new Uri("http://2"), false); ServiceIdentity serviceIdentity2 = new ServiceIdentity("3", new Uri("http://3"), false); ServiceIdentity serviceIdentity3 = new ServiceIdentity("4", new Uri("http://4"), false); CollectionRoutingMap routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( new[] { Tuple.Create( new PartitionKeyRange { Id = "2", MinInclusive = "0000000050", MaxExclusive = "0000000070" }, serviceIdentity2), Tuple.Create( new PartitionKeyRange { Id = "0", MinInclusive = "", MaxExclusive = "0000000030" }, serviceIdentity0), Tuple.Create( new PartitionKeyRange { Id = "1", MinInclusive = "0000000030", MaxExclusive = "0000000050" }, serviceIdentity1), Tuple.Create( new PartitionKeyRange { Id = "3", MinInclusive = "0000000070", MaxExclusive = "FF" }, serviceIdentity3), }, string.Empty); Assert.AreEqual("0", routingMap.OrderedPartitionKeyRanges[0].Id); Assert.AreEqual("1", routingMap.OrderedPartitionKeyRanges[1].Id); Assert.AreEqual("2", routingMap.OrderedPartitionKeyRanges[2].Id); Assert.AreEqual("3", routingMap.OrderedPartitionKeyRanges[3].Id); Assert.AreEqual(serviceIdentity0, routingMap.TryGetInfoByPartitionKeyRangeId("0")); Assert.AreEqual(serviceIdentity1, routingMap.TryGetInfoByPartitionKeyRangeId("1")); Assert.AreEqual(serviceIdentity2, routingMap.TryGetInfoByPartitionKeyRangeId("2")); Assert.AreEqual(serviceIdentity3, routingMap.TryGetInfoByPartitionKeyRangeId("3")); Assert.AreEqual("0", routingMap.GetRangeByEffectivePartitionKey("").Id); Assert.AreEqual("0", routingMap.GetRangeByEffectivePartitionKey("0000000000").Id); Assert.AreEqual("1", routingMap.GetRangeByEffectivePartitionKey("0000000030").Id); Assert.AreEqual("1", routingMap.GetRangeByEffectivePartitionKey("0000000031").Id); Assert.AreEqual("3", routingMap.GetRangeByEffectivePartitionKey("0000000071").Id); Assert.AreEqual("0", routingMap.TryGetRangeByPartitionKeyRangeId("0").Id); Assert.AreEqual("1", routingMap.TryGetRangeByPartitionKeyRangeId("1").Id); Assert.AreEqual(4, routingMap.GetOverlappingRanges(new[] { new Range <string>(PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, true, false) }).Count); Assert.AreEqual(0, routingMap.GetOverlappingRanges(new[] { new Range <string>(PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, false, false) }).Count); IReadOnlyList <PartitionKeyRange> partitionKeyRanges = routingMap.GetOverlappingRanges(new[] { new Range <string>( "0000000040", "0000000040", true, true) }); Assert.AreEqual(1, partitionKeyRanges.Count); Assert.AreEqual("1", partitionKeyRanges.ElementAt(0).Id); IReadOnlyList <PartitionKeyRange> partitionKeyRanges1 = routingMap.GetOverlappingRanges(new[] { new Range <string>( "0000000040", "0000000045", true, true), new Range <string>( "0000000045", "0000000046", true, true), new Range <string>( "0000000046", "0000000050", true, true) }); Assert.AreEqual(2, partitionKeyRanges1.Count); Assert.AreEqual("1", partitionKeyRanges1.ElementAt(0).Id); Assert.AreEqual("2", partitionKeyRanges1.ElementAt(1).Id); }