private async Task <TryCatch <FeedTokenInternal> > TryInitializeFeedTokenAsync(CancellationToken cancellationToken) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.clientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); string containerRId = string.Empty; try { containerRId = await this.container.GetRIDAsync(cancellationToken); } catch (Exception cosmosException) { return(TryCatch <FeedTokenInternal> .FromException(cosmosException)); } IReadOnlyList <Documents.PartitionKeyRange> partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( containerRId, new Documents.Routing.Range <string>( Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, isMinInclusive: true, isMaxInclusive: false), forceRefresh : true); // ReadAll scenario, initialize with one token for all return(TryCatch <FeedTokenInternal> .FromResult(new FeedTokenEPKRange(containerRId, partitionKeyRanges))); }
public override async Task <Documents.ShouldRetryResult> HandleSplitAsync( ContainerInternal containerCore, ResponseMessage responseMessage, CancellationToken cancellationToken) { // Split handling bool partitionSplit = responseMessage.StatusCode == HttpStatusCode.Gone && (responseMessage.Headers.SubStatusCode == Documents.SubStatusCodes.PartitionKeyRangeGone || responseMessage.Headers.SubStatusCode == Documents.SubStatusCodes.CompletingSplit); if (!partitionSplit) { return(FeedRangeCompositeContinuation.NoRetry); } Routing.PartitionKeyRangeCache partitionKeyRangeCache = await containerCore.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); IReadOnlyList <Documents.PartitionKeyRange> resolvedRanges = await this.TryGetOverlappingRangesAsync(partitionKeyRangeCache, this.CurrentToken.Range.Min, this.CurrentToken.Range.Max, forceRefresh : true); if (resolvedRanges.Count > 0) { this.CreateChildRanges(resolvedRanges); } return(FeedRangeCompositeContinuation.Retry); }
private async Task InitializeFeedContinuationAsync(CancellationToken cancellationToken) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.clientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); List <Documents.Routing.Range <string> > ranges; if (this.FeedRangeInternal is FeedRangePartitionKey) { Documents.PartitionKeyDefinition partitionKeyDefinition = await this.container.GetPartitionKeyDefinitionAsync(cancellationToken); ranges = await this.FeedRangeInternal.GetEffectiveRangesAsync(partitionKeyRangeCache, this.lazyContainerRid.Result.Result, partitionKeyDefinition); } else { IReadOnlyList <Documents.PartitionKeyRange> pkRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( collectionRid : this.lazyContainerRid.Result.Result, range : (this.FeedRangeInternal as FeedRangeEPK).Range, forceRefresh : false); ranges = pkRanges.Select(pkRange => pkRange.ToRange()).ToList(); } this.FeedRangeContinuation = new FeedRangeCompositeContinuation( containerRid: this.lazyContainerRid.Result.Result, feedRange: this.FeedRangeInternal, ranges: ranges); }
public async Task <IReadOnlyList <Documents.Routing.Range <string> > > VisitAsync(FeedRangePartitionKeyRange feedRange, CancellationToken cancellationToken = default) { // Migration from PKRangeId scenario Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.container.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); return(await feedRange.GetEffectiveRangesAsync( routingMapProvider : partitionKeyRangeCache, containerRid : await this.container.GetRIDAsync(cancellationToken), partitionKeyDefinition : null)); }
public async Task <IReadOnlyList <Documents.Routing.Range <string> > > VisitAsync(FeedRangeEPK feedRange, CancellationToken cancellationToken = default) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.container.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); IReadOnlyList <PartitionKeyRange> pkRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( collectionRid : await this.container.GetRIDAsync(cancellationToken), range : feedRange.Range, forceRefresh : false); return(pkRanges.Select(pkRange => pkRange.ToRange()).ToList()); }
public async Task <IReadOnlyList <Documents.Routing.Range <string> > > VisitAsync(FeedRangePartitionKey feedRange, CancellationToken cancellationToken = default) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.container.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); PartitionKeyDefinition partitionKeyDefinition = await this.container.GetPartitionKeyDefinitionAsync(cancellationToken); return(await feedRange.GetEffectiveRangesAsync( partitionKeyRangeCache, await this.container.GetRIDAsync(cancellationToken), partitionKeyDefinition)); }
private async Task InitializeFeedContinuationAsync(CancellationToken cancellationToken) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.clientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); List<Documents.Routing.Range<string>> effectiveRanges = await this.FeedRangeInternal.GetEffectiveRangesAsync( routingMapProvider: partitionKeyRangeCache, containerRid: this.lazyContainerRid.Result.Result, partitionKeyDefinition: null); this.FeedRangeContinuation = new FeedRangeCompositeContinuation( containerRid: this.lazyContainerRid.Result.Result, feedRange: this.FeedRangeInternal, effectiveRanges); }
public override async Task <bool> ShouldRetryAsync( ContainerCore containerCore, ResponseMessage responseMessage, CancellationToken cancellationToken = default(CancellationToken)) { if (this.FeedTokenEPKRange != null) { return(await this.FeedTokenEPKRange.ShouldRetryAsync(containerCore, responseMessage, cancellationToken)); } if (responseMessage.IsSuccessStatusCode) { return(false); } bool partitionSplit = responseMessage.StatusCode == HttpStatusCode.Gone && (responseMessage.Headers.SubStatusCode == Documents.SubStatusCodes.PartitionKeyRangeGone || responseMessage.Headers.SubStatusCode == Documents.SubStatusCodes.CompletingSplit); if (partitionSplit) { string containerRid = await containerCore.GetRIDAsync(cancellationToken); Routing.PartitionKeyRangeCache partitionKeyRangeCache = await containerCore.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); IReadOnlyList <Documents.PartitionKeyRange> keyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( containerRid, new Documents.Routing.Range <string>( Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, isMaxInclusive: false, isMinInclusive: true), forceRefresh : true); List <Documents.PartitionKeyRange> addedRanges = keyRanges.Where(range => range.Parents.Contains(this.PartitionKeyRangeId)).ToList(); if (addedRanges.Count == 0) { DefaultTrace.TraceError("FeedTokenPartitionKeyRange - Could not obtain children after split for {0}", this.PartitionKeyRangeId); return(false); } this.FeedTokenEPKRange = new FeedTokenEPKRange(containerRid, new Documents.Routing.Range <string>(addedRanges[0].MinInclusive, addedRanges[addedRanges.Count - 1].MaxExclusive, true, false), addedRanges.Select(range => FeedTokenEPKRange.CreateCompositeContinuationTokenForRange(range.MinInclusive, range.MaxExclusive, this.continuationToken)).ToList()); return(true); } return(false); }
private async Task InitializeFeedContinuationAsync(CancellationToken cancellationToken) { if (this.FeedRangeContinuation == null) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.clientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); List <Documents.Routing.Range <string> > ranges; if (this.FeedRangeInternal is FeedRangePartitionKey) { PartitionKeyDefinition partitionKeyDefinition = await this.container.GetPartitionKeyDefinitionAsync(cancellationToken); ranges = await this.FeedRangeInternal.GetEffectiveRangesAsync(partitionKeyRangeCache, this.lazyContainerRid.Result.Result, partitionKeyDefinition); } else { IReadOnlyList <PartitionKeyRange> pkRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( collectionRid : this.lazyContainerRid.Result.Result, range : (this.FeedRangeInternal as FeedRangeEPK).Range, forceRefresh : false); ranges = pkRanges.Select(pkRange => pkRange.ToRange()).ToList(); } this.FeedRangeContinuation = new FeedRangeCompositeContinuation( containerRid: this.lazyContainerRid.Result.Result, feedRange: this.FeedRangeInternal, ranges: ranges); } else if (this.FeedRangeInternal is FeedRangePartitionKeyRange) { // Migration from PKRangeId scenario Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.clientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); List <Documents.Routing.Range <string> > effectiveRanges = await this.FeedRangeInternal.GetEffectiveRangesAsync( routingMapProvider : partitionKeyRangeCache, containerRid : this.lazyContainerRid.Result.Result, partitionKeyDefinition : null); // Override the original PKRangeId based FeedRange this.FeedRangeInternal = new FeedRangeEPK(effectiveRanges[0]); this.FeedRangeContinuation = new FeedRangeCompositeContinuation( containerRid: this.lazyContainerRid.Result.Result, feedRange: this.FeedRangeInternal, ranges: effectiveRanges, continuation: this.FeedRangeContinuation.GetContinuation()); } }
public override async Task <IEnumerable <string> > GetChangeFeedTokensAsync(CancellationToken cancellationToken = default(CancellationToken)) { Routing.PartitionKeyRangeCache pkRangeCache = await this.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); string containerRid = await this.GetRIDAsync(cancellationToken); IReadOnlyList <Documents.PartitionKeyRange> allRanges = await pkRangeCache.TryGetOverlappingRangesAsync( containerRid, new Documents.Routing.Range <string>( Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, isMinInclusive: true, isMaxInclusive: false), true); return(allRanges.Select(e => StandByFeedContinuationToken.CreateForRange(containerRid, e.MinInclusive, e.MaxExclusive))); }
public override async Task <bool> ShouldRetryAsync( ContainerCore containerCore, ResponseMessage responseMessage, CancellationToken cancellationToken = default(CancellationToken)) { if (responseMessage.IsSuccessStatusCode) { this.initialNoResultsRange = null; return(false); } // If the current response is NotModified (ChangeFeed), try and skip to a next one if (responseMessage.StatusCode == HttpStatusCode.NotModified && this.CompositeContinuationTokens.Count > 1) { if (this.initialNoResultsRange == null) { this.initialNoResultsRange = this.currentToken.Range.Min; return(true); } return(!this.initialNoResultsRange.Equals(this.currentToken.Range.Min, StringComparison.OrdinalIgnoreCase)); } // Split handling bool partitionSplit = responseMessage.StatusCode == HttpStatusCode.Gone && (responseMessage.Headers.SubStatusCode == Documents.SubStatusCodes.PartitionKeyRangeGone || responseMessage.Headers.SubStatusCode == Documents.SubStatusCodes.CompletingSplit); if (partitionSplit) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await containerCore.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); IReadOnlyList <Documents.PartitionKeyRange> resolvedRanges = await this.TryGetOverlappingRangesAsync(partitionKeyRangeCache, this.currentToken.Range.Min, this.currentToken.Range.Max, forceRefresh : true); if (resolvedRanges.Count > 0) { this.HandleSplit(resolvedRanges); } return(true); } return(false); }
public GlobalAddressResolver( GlobalEndpointManager endpointManager, Protocol protocol, IAuthorizationTokenProvider tokenProvider, CollectionCache collectionCache, PartitionKeyRangeCache routingMapProvider, UserAgentContainer userAgentContainer, IServiceConfigurationReader serviceConfigReader, HttpMessageHandler messageHandler, ConnectionPolicy connectionPolicy, ApiType apiType) { this.endpointManager = endpointManager; this.protocol = protocol; this.tokenProvider = tokenProvider; this.userAgentContainer = userAgentContainer; this.collectionCache = collectionCache; this.routingMapProvider = routingMapProvider; this.serviceConfigReader = serviceConfigReader; this.messageHandler = messageHandler; this.requestTimeout = connectionPolicy.RequestTimeout; this.apiType = apiType; int maxBackupReadEndpoints = !connectionPolicy.EnableReadRequestsFallback.HasValue || connectionPolicy.EnableReadRequestsFallback.Value ? GlobalAddressResolver.MaxBackupReadRegions : 0; this.enableTcpConnectionEndpointRediscovery = connectionPolicy.EnableTcpConnectionEndpointRediscovery; this.maxEndpoints = maxBackupReadEndpoints + 2; // for write and alternate write endpoint (during failover) this.addressCacheByEndpoint = new ConcurrentDictionary <Uri, EndpointCache>(); foreach (Uri endpoint in endpointManager.WriteEndpoints) { this.GetOrAddEndpoint(endpoint); } foreach (Uri endpoint in endpointManager.ReadEndpoints) { this.GetOrAddEndpoint(endpoint); } }
public GlobalAddressResolver( GlobalEndpointManager endpointManager, GlobalPartitionEndpointManager partitionKeyRangeLocationCache, Protocol protocol, ICosmosAuthorizationTokenProvider tokenProvider, CollectionCache collectionCache, PartitionKeyRangeCache routingMapProvider, IServiceConfigurationReader serviceConfigReader, ConnectionPolicy connectionPolicy, CosmosHttpClient httpClient) { this.endpointManager = endpointManager; this.partitionKeyRangeLocationCache = partitionKeyRangeLocationCache; this.protocol = protocol; this.tokenProvider = tokenProvider; this.collectionCache = collectionCache; this.routingMapProvider = routingMapProvider; this.serviceConfigReader = serviceConfigReader; this.httpClient = httpClient; int maxBackupReadEndpoints = !connectionPolicy.EnableReadRequestsFallback.HasValue || connectionPolicy.EnableReadRequestsFallback.Value ? GlobalAddressResolver.MaxBackupReadRegions : 0; this.enableTcpConnectionEndpointRediscovery = connectionPolicy.EnableTcpConnectionEndpointRediscovery; this.maxEndpoints = maxBackupReadEndpoints + 2; // for write and alternate write endpoint (during failover) this.addressCacheByEndpoint = new ConcurrentDictionary <Uri, EndpointCache>(); foreach (Uri endpoint in endpointManager.WriteEndpoints) { this.GetOrAddEndpoint(endpoint); } foreach (Uri endpoint in endpointManager.ReadEndpoints) { this.GetOrAddEndpoint(endpoint); } }
private async Task <IReadOnlyList <Documents.PartitionKeyRange> > TryGetOverlappingRangesAsync( Routing.PartitionKeyRangeCache partitionKeyRangeCache, string min, string max, bool forceRefresh = false) { IReadOnlyList <Documents.PartitionKeyRange> keyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( this.ContainerRid, new Documents.Routing.Range <string>( min, max, isMaxInclusive: false, isMinInclusive: true), forceRefresh); if (keyRanges.Count == 0) { throw new ArgumentOutOfRangeException("RequestContinuation", $"Token contains invalid range {min}-{max}"); } return(keyRanges); }
public virtual async Task <CollectionRoutingMap> TryLookupAsync( string collectionRid, CollectionRoutingMap previousValue, DocumentServiceRequest request, ITrace trace) { try { return(await this.routingMapCache.GetAsync( key : collectionRid, singleValueInitFunc : (_) => this.GetRoutingMapForCollectionAsync( collectionRid, previousValue, trace, request?.RequestContext?.ClientRequestStatistics), forceRefresh : (currentValue) => PartitionKeyRangeCache.ShouldForceRefresh(previousValue, currentValue))); } catch (DocumentClientException ex) { if (previousValue != null) { StringBuilder rangesString = new StringBuilder(); foreach (PartitionKeyRange range in previousValue.OrderedPartitionKeyRanges) { rangesString.Append(range.ToRange().ToString()); rangesString.Append(", "); } DefaultTrace.TraceInformation(string.Format("DocumentClientException in TryLookupAsync Collection: {0}, previousValue: {1} Exception: {2}", collectionRid, rangesString.ToString(), ex.ToString())); } if (ex.StatusCode == HttpStatusCode.NotFound) { return(null); } throw; } }
private async Task <ResponseMessage> ReadNextInternalAsync( CosmosDiagnosticsContext diagnosticsScope, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); if (this.feedTokenInternal == null) { Routing.PartitionKeyRangeCache partitionKeyRangeCache = await this.clientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(); string containerRId = await this.container.GetRIDAsync(cancellationToken); IReadOnlyList <Documents.PartitionKeyRange> partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync( containerRId, new Documents.Routing.Range <string>( Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, isMinInclusive: true, isMaxInclusive: false), forceRefresh : true); // ReadAll scenario, initialize with one token for all this.feedTokenInternal = new FeedTokenEPKRange(containerRId, partitionKeyRanges); } Uri resourceUri = this.container.LinkUri; ResponseMessage responseMessage = await this.clientContext.ProcessResourceOperationStreamAsync( resourceUri : resourceUri, resourceType : Documents.ResourceType.Document, operationType : Documents.OperationType.ReadFeed, requestOptions : this.changeFeedOptions, cosmosContainerCore : this.container, requestEnricher : request => { ChangeFeedRequestOptions.FillContinuationToken(request, this.feedTokenInternal.GetContinuation()); this.feedTokenInternal.EnrichRequest(request); }, partitionKey : null, streamPayload : null, diagnosticsScope : diagnosticsScope, cancellationToken : cancellationToken); // Retry in case of splits or other scenarios if (await this.feedTokenInternal.ShouldRetryAsync(this.container, responseMessage, cancellationToken)) { if (responseMessage.IsSuccessStatusCode || responseMessage.StatusCode == HttpStatusCode.NotModified) { // Change Feed read uses Etag for continuation this.feedTokenInternal.UpdateContinuation(responseMessage.Headers.ETag); } return(await this.ReadNextInternalAsync(diagnosticsScope, cancellationToken)); } if (responseMessage.IsSuccessStatusCode || responseMessage.StatusCode == HttpStatusCode.NotModified) { // Change Feed read uses Etag for continuation this.feedTokenInternal.UpdateContinuation(responseMessage.Headers.ETag); } this.hasMoreResults = responseMessage.IsSuccessStatusCode; return(responseMessage); }