public void DefaultIncludesShouldNotBePopulated() { CosmosContainerProperties containerSettings = new CosmosContainerProperties("TestContainer", "/partitionKey"); Assert.IsNotNull(containerSettings.IndexingPolicy); // Any exclude path should not auto-generate default indexing containerSettings.IndexingPolicy = new IndexingPolicy(); containerSettings.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath() { Path = "/some" }); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); containerSettings.ValidateRequiredProperties(); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); // None indexing mode should not auto-generate the default indexing containerSettings.IndexingPolicy = new IndexingPolicy { IndexingMode = IndexingMode.None }; Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); containerSettings.ValidateRequiredProperties(); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); }
private static void EnsureRoutingMapPresent( DocumentServiceRequest request, CollectionRoutingMap routingMap, CosmosContainerProperties collection) { if (routingMap == null && request.IsNameBased && request.PartitionKeyRangeIdentity != null && request.PartitionKeyRangeIdentity.CollectionRid != null) { // By design, if partitionkeyrangeid header is present and it contains collectionrid for collection // which doesn't exist, we return InvalidPartitionException. Backend does the same. // Caller (client SDK or whoever attached the header) supposedly has outdated collection cache and will refresh it. // We cannot retry here, as the logic for retry in this case is use-case specific. DefaultTrace.TraceInformation( "Routing map for request with partitionkeyrageid {0} was not found", request.PartitionKeyRangeIdentity.ToHeader()); throw new InvalidPartitionException() { ResourceAddress = request.ResourceAddress }; } if (routingMap == null) { DefaultTrace.TraceInformation( "Routing map was not found although collection cache is upto date for collection {0}", collection.ResourceId); // Routing map not found although collection was resolved correctly. throw new NotFoundException() { ResourceAddress = request.ResourceAddress }; } }
private async Task <ShouldRetryResult> ShouldRetryInternalAsync( HttpStatusCode?statusCode, SubStatusCodes?subStatusCode, ShouldRetryResult shouldRetryResult, CancellationToken cancellationToken) { if (this.request == null) { // someone didn't call OnBeforeSendRequest - nothing we can do DefaultTrace.TraceCritical("Cannot apply RenameCollectionAwareClientRetryPolicy as OnBeforeSendRequest has not been called and there is no DocumentServiceRequest context."); return(shouldRetryResult); } Debug.Assert(shouldRetryResult != null); if (!shouldRetryResult.ShouldRetry && !this.hasTriggered && statusCode.HasValue && subStatusCode.HasValue) { if (this.request.IsNameBased && statusCode.Value == HttpStatusCode.NotFound && subStatusCode.Value == SubStatusCodes.ReadSessionNotAvailable) { // Clear the session token, because the collection name might be reused. DefaultTrace.TraceWarning("Clear the the token for named base request {0}", request.ResourceAddress); this.sessionContainer.ClearTokenByCollectionFullname(request.ResourceAddress); this.hasTriggered = true; string oldCollectionRid = request.RequestContext.ResolvedCollectionRid; request.ForceNameCacheRefresh = true; request.RequestContext.ResolvedCollectionRid = null; try { CosmosContainerProperties collectionInfo = await this.collectionCache.ResolveCollectionAsync(request, cancellationToken); if (collectionInfo == null) { DefaultTrace.TraceCritical("Can't recover from session unavailable exception because resolving collection name {0} returned null", request.ResourceAddress); } else if (!string.IsNullOrEmpty(oldCollectionRid) && !string.IsNullOrEmpty(collectionInfo.ResourceId)) { if (!oldCollectionRid.Equals(collectionInfo.ResourceId)) { return(ShouldRetryResult.RetryAfter(TimeSpan.Zero)); } } } catch (Exception e) { // When ResolveCollectionAsync throws an exception ignore it because it's an attempt to recover an existing // error. When the recovery fails we return ShouldRetryResult.NoRetry and propaganate the original exception to the client DefaultTrace.TraceCritical("Can't recover from session unavailable exception because resolving collection name {0} failed with {1}", request.ResourceAddress, e.ToString()); } } } return(shouldRetryResult); }
public void ValidateSerialization() { CosmosJsonSerializerCore jsonSerializer = new CosmosJsonSerializerCore(); CosmosContainerProperties containerSettings = new CosmosContainerProperties("TestContainer", "/partitionKey"); Stream basic = jsonSerializer.ToStream <CosmosContainerProperties>(containerSettings); CosmosContainerProperties response = jsonSerializer.FromStream <CosmosContainerProperties>(basic); Assert.AreEqual(containerSettings.Id, response.Id); Assert.AreEqual(containerSettings.PartitionKeyPath, response.PartitionKeyPath); }
internal Task <ContainerResponse> CreateContainerResponseAsync( CosmosContainer container, Task <CosmosResponseMessage> cosmosResponseMessageTask) { return(this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { CosmosContainerProperties settings = this.ToObjectInternal <CosmosContainerProperties>(cosmosResponseMessage, this.settingsSerializer); return new ContainerResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, settings, container); })); }
private async Task <ShouldRetryResult> ShouldRetryInternalAsync( HttpStatusCode?statusCode, SubStatusCodes?subStatusCode, CancellationToken cancellationToken) { if (!statusCode.HasValue && (!subStatusCode.HasValue || subStatusCode.Value == SubStatusCodes.Unknown)) { return(null); } if (statusCode == HttpStatusCode.Gone && subStatusCode == SubStatusCodes.PartitionKeyRangeGone) { if (this.retried) { return(ShouldRetryResult.NoRetry()); } using (DocumentServiceRequest request = DocumentServiceRequest.Create( OperationType.Read, ResourceType.Collection, this.collectionLink, null, AuthorizationTokenType.PrimaryMasterKey)) { CosmosContainerProperties collection = await this.collectionCache.ResolveCollectionAsync(request, cancellationToken); CollectionRoutingMap routingMap = await this.partitionKeyRangeCache.TryLookupAsync(collection.ResourceId, null, request, cancellationToken); if (routingMap != null) { // Force refresh. await this.partitionKeyRangeCache.TryLookupAsync( collection.ResourceId, routingMap, request, cancellationToken); } } this.retried = true; return(ShouldRetryResult.RetryAfter(TimeSpan.FromSeconds(0))); } return(null); }
public override Task <CosmosResponseMessage> ReplaceStreamAsync( CosmosContainerProperties containerSettings, ContainerRequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { if (containerSettings == null) { throw new ArgumentNullException(nameof(containerSettings)); } this.ClientContext.ValidateResource(containerSettings.Id); return(this.ReplaceStreamInternalAsync( streamPayload: this.ClientContext.SettingsSerializer.ToStream(containerSettings), requestOptions: requestOptions, cancellationToken: cancellationToken)); }
/// <summary> /// Used by typed API only. Exceptions are allowed. /// </summary> /// <param name="cancellationToken"></param> /// <returns>Returns the partition key path</returns> internal virtual async Task <string[]> GetPartitionKeyPathTokensAsync(CancellationToken cancellationToken = default(CancellationToken)) { CosmosContainerProperties containerSettings = await this.GetCachedContainerSettingsAsync(cancellationToken); if (containerSettings == null) { throw new ArgumentOutOfRangeException($"Container {this.LinkUri.ToString()} not found"); } if (containerSettings.PartitionKey?.Paths == null) { throw new ArgumentOutOfRangeException($"Partition key not defined for container {this.LinkUri.ToString()}"); } return(containerSettings.PartitionKeyPathTokens); }
private static void AssertSerializedPayloads(CosmosContainerProperties settings, DocumentCollection documentCollection) { JsonSerializerSettings jsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; // HAKC: Work-around till BE fixes defautls settings.ValidateRequiredProperties(); string containerSerialized = JsonConvert.SerializeObject(settings, jsonSettings); string collectionSerialized = CosmosContainerSettingsTests.SerializeDocumentCollection(documentCollection); JObject containerJObject = JObject.Parse(containerSerialized); JObject collectionJObject = JObject.Parse(collectionSerialized); Assert.AreEqual(JsonConvert.SerializeObject(OrderProeprties(collectionJObject)), JsonConvert.SerializeObject(OrderProeprties(containerJObject))); }
public void DefaultSameAsDocumentCollection() { CosmosContainerProperties containerSettings = new CosmosContainerProperties("TestContainer", "/partitionKey"); DocumentCollection dc = new DocumentCollection() { Id = "TestContainer", PartitionKey = new PartitionKeyDefinition() { Paths = new Collection <string>() { "/partitionKey" } } }; CosmosContainerSettingsTests.AssertSerializedPayloads(containerSettings, dc); }
public void DefaultIncludesPopulated() { CosmosContainerProperties containerSettings = new CosmosContainerProperties("TestContainer", "/partitionKey"); Assert.IsNotNull(containerSettings.IndexingPolicy); containerSettings.IndexingPolicy = new IndexingPolicy(); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); // HAKC: Work-around till BE fixes defautls containerSettings.ValidateRequiredProperties(); Assert.AreEqual(1, containerSettings.IndexingPolicy.IncludedPaths.Count); IncludedPath defaultEntry = containerSettings.IndexingPolicy.IncludedPaths[0]; Assert.AreEqual(IndexingPolicy.DefaultPath, defaultEntry.Path); Assert.AreEqual(0, defaultEntry.Indexes.Count); }
private async Task <ResolutionResult> TryResolveServerPartitionByPartitionKeyRangeIdAsync( DocumentServiceRequest request, CosmosContainerProperties 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)); }
/// <summary> /// Creates a container as an asynchronous operation in the Azure Cosmos service. /// </summary> /// <param name="containerSettings">The <see cref="CosmosContainerProperties"/> object.</param> /// <param name="requestUnitsPerSecond">(Optional) The throughput provisioned for a container in measurement of Request Units per second in the Azure Cosmos DB service.</param> /// <param name="requestOptions">(Optional) The options for the container request <see cref="RequestOptions"/></param> /// <param name="cancellationToken">(Optional) <see cref="CancellationToken"/> representing request cancellation.</param> /// <returns>A <see cref="Task"/> containing a <see cref="CosmosResponseMessage"/> containing the created resource record.</returns> /// <seealso cref="DefineContainer(string, string)"/> /// <remarks> /// <seealso href="https://docs.microsoft.com/azure/cosmos-db/request-units"/> for details on provision throughput. /// </remarks> public abstract Task <CosmosResponseMessage> CreateContainerStreamAsync( CosmosContainerProperties containerSettings, int?requestUnitsPerSecond = null, RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken));
private PartitionKeyRange TryResolveServerPartitionByPartitionKey( DocumentServiceRequest request, string partitionKeyString, bool collectionCacheUptoDate, CosmosContainerProperties collection, CollectionRoutingMap routingMap) { if (request == null) { throw new ArgumentNullException("request"); } if (partitionKeyString == null) { throw new ArgumentNullException("partitionKeyString"); } if (collection == null) { throw new ArgumentNullException("collection"); } if (routingMap == null) { throw new ArgumentNullException("routingMap"); } PartitionKeyInternal partitionKey; try { partitionKey = PartitionKeyInternal.FromJsonString(partitionKeyString); } catch (JsonException ex) { throw new BadRequestException( string.Format(CultureInfo.InvariantCulture, RMResources.InvalidPartitionKey, partitionKeyString), ex) { ResourceAddress = request.ResourceAddress }; } if (partitionKey == null) { throw new InternalServerErrorException(string.Format(CultureInfo.InvariantCulture, "partition key is null '{0}'", partitionKeyString)); } if (partitionKey.Equals(PartitionKeyInternal.Empty) || partitionKey.Components.Count == collection.PartitionKey.Paths.Count) { // Although we can compute effective partition key here, in general case this Gateway can have outdated // partition key definition cached - like if collection with same name but with Range partitioning is created. // In this case server will not pass x-ms-documentdb-collection-rid check and will return back InvalidPartitionException. // Gateway will refresh its cache and retry. string effectivePartitionKey = partitionKey.GetEffectivePartitionKeyString(collection.PartitionKey); // There should be exactly one range which contains a partition key. Always. return(routingMap.GetRangeByEffectivePartitionKey(effectivePartitionKey)); } if (collectionCacheUptoDate) { BadRequestException badRequestException = new BadRequestException(RMResources.PartitionKeyMismatch) { ResourceAddress = request.ResourceAddress }; badRequestException.Headers[WFConstants.BackendHeaders.SubStatus] = ((uint)SubStatusCodes.PartitionKeyMismatch).ToString(CultureInfo.InvariantCulture); throw badRequestException; } // Partition key supplied has different number paths than locally cached partition key definition. // Three things can happen: // 1. User supplied wrong partition key. // 2. Client SDK has outdated partition key definition cache and extracted wrong value from the document. // 3. Gateway's cache is outdated. // // What we will do is append x-ms-documentdb-collection-rid header and forward it to random collection partition. // * If collection rid matches, server will send back 400.1001, because it also will not be able to compute // effective partition key. Gateway will forward this status code to client - client will handle it. // * If collection rid doesn't match, server will send back InvalidPartiitonException and Gateway will // refresh name routing cache - this will refresh partition key definition as well, and retry. DefaultTrace.TraceInformation( "Cannot compute effective partition key. Definition has '{0}' paths, values supplied has '{1}' paths. Will refresh cache and retry.", collection.PartitionKey.Paths.Count, partitionKey.Components.Count); return(null); }
private async Task <ResolutionResult> TryResolveServerPartitionAsync( DocumentServiceRequest request, CosmosContainerProperties 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)); }
/// <summary> /// Resolves the endpoint of the partition for the given request /// </summary> /// <param name="request">Request for which the partition endpoint resolution is to be performed</param> /// <param name="forceRefreshPartitionAddresses">Force refresh the partition's endpoint</param> /// <param name="cancellationToken">Cancellation token</param> /// <returns>An instance of <see cref="ResolutionResult"/>.</returns> private async Task <ResolutionResult> ResolveAddressesAndIdentityAsync( DocumentServiceRequest request, bool forceRefreshPartitionAddresses, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (request.ServiceIdentity != null) { // In this case we don't populate request.RequestContext.ResolvedPartitionKeyRangeId, // which is needed for session token. // The assumption is that: // 1. Master requests never use session consistency. // 2. Service requests (like collection create etc.) don't use session consistency. // 3. Requests which target specific partition of an existing collection will use x-ms-documentdb-partitionkeyrangeid header // to send request to specific partition and will not set request.ServiceIdentity ServiceIdentity identity = request.ServiceIdentity; PartitionAddressInformation addresses = await this.addressCache.TryGetAddressesAsync(request, null, identity, forceRefreshPartitionAddresses, cancellationToken); if (addresses == null) { DefaultTrace.TraceInformation("Could not get addresses for explicitly specified ServiceIdentity {0}", identity); throw new NotFoundException() { ResourceAddress = request.ResourceAddress }; } return(new ResolutionResult(addresses, identity)); } if (ReplicatedResourceClient.IsReadingFromMaster(request.ResourceType, request.OperationType) && request.PartitionKeyRangeIdentity == null) { DefaultTrace.TraceInformation("Resolving Master service address, forceMasterRefresh: {0}, currentMaster: {1}", request.ForceMasterRefresh, this.masterServiceIdentityProvider?.MasterServiceIdentity); // Client implementation, GlobalAddressResolver passes in a null IMasterServiceIdentityProvider, because it doesn't actually use the serviceIdentity // in the addressCache.TryGetAddresses method. In GatewayAddressCache.cs, the master address is resolved by making a call to Gateway AddressFeed, // not using the serviceIdentity that is passed in if (request.ForceMasterRefresh && this.masterServiceIdentityProvider != null) { ServiceIdentity previousMasterService = this.masterServiceIdentityProvider.MasterServiceIdentity; await this.masterServiceIdentityProvider.RefreshAsync(previousMasterService, cancellationToken); } ServiceIdentity serviceIdentity = this.masterServiceIdentityProvider?.MasterServiceIdentity; PartitionKeyRangeIdentity partitionKeyRangeIdentity = this.masterPartitionKeyRangeIdentity; PartitionAddressInformation addresses = await this.addressCache.TryGetAddressesAsync( request, partitionKeyRangeIdentity, serviceIdentity, forceRefreshPartitionAddresses, cancellationToken); if (addresses == null) { // This shouldn't really happen. DefaultTrace.TraceCritical("Could not get addresses for master partition {0}", serviceIdentity); throw new NotFoundException() { ResourceAddress = request.ResourceAddress }; } PartitionKeyRange partitionKeyRange = new PartitionKeyRange { Id = PartitionKeyRange.MasterPartitionKeyRangeId }; return(new ResolutionResult(partitionKeyRange, addresses, serviceIdentity)); } bool collectionCacheIsUptoDate = !request.IsNameBased || (request.PartitionKeyRangeIdentity != null && request.PartitionKeyRangeIdentity.CollectionRid != null); bool collectionRoutingMapCacheIsUptoDate = false; CosmosContainerProperties collection = await this.collectionCache.ResolveCollectionAsync(request, cancellationToken); CollectionRoutingMap routingMap = await this.collectionRoutingMapCache.TryLookupAsync( collection.ResourceId, null, request, cancellationToken); if (routingMap != null && request.ForceCollectionRoutingMapRefresh) { DefaultTrace.TraceInformation( "AddressResolver.ResolveAddressesAndIdentityAsync ForceCollectionRoutingMapRefresh collection.ResourceId = {0}", collection.ResourceId); routingMap = await this.collectionRoutingMapCache.TryLookupAsync(collection.ResourceId, routingMap, request, cancellationToken); } if (request.ForcePartitionKeyRangeRefresh) { collectionRoutingMapCacheIsUptoDate = true; request.ForcePartitionKeyRangeRefresh = false; if (routingMap != null) { routingMap = await this.collectionRoutingMapCache.TryLookupAsync(collection.ResourceId, routingMap, request, cancellationToken); } } if (routingMap == null && !collectionCacheIsUptoDate) { // Routing map was not found by resolved collection rid. Maybe collection rid is outdated. // Refresh collection cache and reresolve routing map. request.ForceNameCacheRefresh = true; collectionCacheIsUptoDate = true; collectionRoutingMapCacheIsUptoDate = false; collection = await this.collectionCache.ResolveCollectionAsync(request, cancellationToken); routingMap = await this.collectionRoutingMapCache.TryLookupAsync( collection.ResourceId, previousValue : null, request : request, cancellationToken : cancellationToken); } AddressResolver.EnsureRoutingMapPresent(request, routingMap, collection); // At this point we have both collection and routingMap. ResolutionResult result = await this.TryResolveServerPartitionAsync( request, collection, routingMap, collectionCacheIsUptoDate, collectionRoutingMapCacheIsUptodate : collectionRoutingMapCacheIsUptoDate, forceRefreshPartitionAddresses : forceRefreshPartitionAddresses, cancellationToken : cancellationToken); if (result == null) { // Couldn't resolve server partition or its addresses. // Either collection cache is outdated or routing map cache is outdated. if (!collectionCacheIsUptoDate) { request.ForceNameCacheRefresh = true; collectionCacheIsUptoDate = true; collection = await this.collectionCache.ResolveCollectionAsync(request, cancellationToken); if (collection.ResourceId != routingMap.CollectionUniqueId) { // Collection cache was stale. We resolved to new Rid. routing map cache is potentially stale // for this new collection rid. Mark it as such. collectionRoutingMapCacheIsUptoDate = false; routingMap = await this.collectionRoutingMapCache.TryLookupAsync( collection.ResourceId, previousValue : null, request : request, cancellationToken : cancellationToken); } } if (!collectionRoutingMapCacheIsUptoDate) { collectionRoutingMapCacheIsUptoDate = true; routingMap = await this.collectionRoutingMapCache.TryLookupAsync( collection.ResourceId, previousValue : routingMap, request : request, cancellationToken : cancellationToken); } AddressResolver.EnsureRoutingMapPresent(request, routingMap, collection); result = await this.TryResolveServerPartitionAsync( request, collection, routingMap, collectionCacheIsUptodate : true, collectionRoutingMapCacheIsUptodate : true, forceRefreshPartitionAddresses : forceRefreshPartitionAddresses, cancellationToken : cancellationToken); } if (result == null) { DefaultTrace.TraceInformation("Couldn't route partitionkeyrange-oblivious request after retry/cache refresh. Collection doesn't exist."); // At this point collection cache and routing map caches are refreshed. // The only reason we will get here is if collection doesn't exist. // Case when partitionkeyrange doesn't exist is handled in the corresponding method. throw new NotFoundException() { ResourceAddress = request.ResourceAddress }; } if (request.IsNameBased) { // Append collection rid. // If we resolved collection rid incorrectly because of outdated cache, this can lead // to incorrect routing decisions. But backend will validate collection rid and throw // InvalidPartitionException if we reach wrong collection. // Also this header will be used by backend to inject collection rid into metrics for // throttled requests. request.Headers[WFConstants.BackendHeaders.CollectionRid] = collection.ResourceId; } return(result); }
/// <summary> /// Instantiates a new instance of the <see cref="PartitionKeyInternal"/> object. /// </summary> /// <remarks> /// The function selects the right partition key constant for inserting documents that don't have /// a value for partition key. The constant selection is based on whether the collection is migrated /// or user partitioned /// /// For non-existing container will throw <see cref="DocumentClientException"/> with 404 as status code /// </remarks> internal async Task <PartitionKeyInternal> GetNonePartitionKeyValueAsync(CancellationToken cancellationToken = default(CancellationToken)) { CosmosContainerProperties containerSettings = await this.GetCachedContainerSettingsAsync(cancellationToken); return(containerSettings.GetNoneValue()); }