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)));
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 12
0
        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);
            }
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
        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;
            }
        }
Ejemplo n.º 16
0
        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);
        }