Ejemplo n.º 1
0
        public async Task <IReadOnlyList <FeedRange> > GetFeedRangesAsync(
            ITrace trace,
            CancellationToken cancellationToken = default)
        {
            PartitionKeyRangeCache partitionKeyRangeCache = await this.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(trace);

            string containerRId;

            containerRId = await this.GetCachedRIDAsync(
                forceRefresh : false,
                trace,
                cancellationToken);

            IReadOnlyList <PartitionKeyRange> partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync(
                containerRId,
                ContainerCore.allRanges,
                trace,
                forceRefresh : true);

            if (partitionKeyRanges == null)
            {
                string refreshedContainerRId;
                refreshedContainerRId = await this.GetCachedRIDAsync(
                    forceRefresh : true,
                    trace,
                    cancellationToken);

                if (string.Equals(containerRId, refreshedContainerRId))
                {
                    throw CosmosExceptionFactory.CreateInternalServerErrorException(
                              $"Container rid {containerRId} did not have a partition key range after refresh",
                              headers: new Headers(),
                              trace: trace);
                }

                partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync(
                    containerRId,
                    ContainerCore.allRanges,
                    trace,
                    forceRefresh : true);

                if (partitionKeyRanges == null)
                {
                    throw CosmosExceptionFactory.CreateInternalServerErrorException(
                              $"Container rid {containerRId} returned partitionKeyRanges null after Container RID refresh",
                              headers: new Headers(),
                              trace: trace);
                }
            }

            List <FeedRange> feedTokens = new List <FeedRange>(partitionKeyRanges.Count);

            foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges)
            {
                feedTokens.Add(new FeedRangeEpk(partitionKeyRange.ToRange()));
            }

            return(feedTokens);
        }
Ejemplo n.º 2
0
        public async Task <IReadOnlyList <FeedRange> > GetFeedRangesAsync(
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken = default)
        {
            PartitionKeyRangeCache partitionKeyRangeCache = await this.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync();

            string containerRId = await this.GetRIDAsync(cancellationToken);

            IReadOnlyList <PartitionKeyRange> partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync(
                containerRId,
                new Range <string>(
                    PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey,
                    PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey,
                    isMinInclusive : true,
                    isMaxInclusive : false),
                forceRefresh : true);

            List <FeedRange> feedTokens = new List <FeedRange>(partitionKeyRanges.Count);

            foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges)
            {
                feedTokens.Add(new FeedRangeEpk(partitionKeyRange.ToRange()));
            }

            return(feedTokens);
        }
        private async Task <ShouldRetryResult> ShouldRetryInternalAsync(
            HttpStatusCode?statusCode,
            SubStatusCodes?subStatusCode,
            CancellationToken cancellationToken)
        {
            if (statusCode == HttpStatusCode.Gone)
            {
                if (subStatusCode == SubStatusCodes.PartitionKeyRangeGone ||
                    subStatusCode == SubStatusCodes.CompletingSplit ||
                    subStatusCode == SubStatusCodes.CompletingPartitionMigration)
                {
                    PartitionKeyRangeCache partitionKeyRangeCache = await this.container.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync();

                    string containerRid = await this.container.GetCachedRIDAsync(forceRefresh : false, cancellationToken : cancellationToken);

                    await partitionKeyRangeCache.TryGetOverlappingRangesAsync(containerRid, FeedRangeEpk.FullRange.Range, forceRefresh : true);

                    return(ShouldRetryResult.RetryAfter(TimeSpan.Zero));
                }

                if (subStatusCode == SubStatusCodes.NameCacheIsStale)
                {
                    return(ShouldRetryResult.RetryAfter(TimeSpan.Zero));
                }
            }

            return(null);
        }
Ejemplo n.º 4
0
        public override async Task <IReadOnlyList <PartitionKeyRange> > TryGetOverlappingRangesAsync(
            string collectionResourceId,
            Range <string> range,
            bool forceRefresh = false)
        {
            PartitionKeyRangeCache partitionKeyRangeCache = await this.GetRoutingMapProviderAsync();

            return(await partitionKeyRangeCache.TryGetOverlappingRangesAsync(collectionResourceId, range, forceRefresh));
        }
        private async Task <ShouldRetryResult> ShouldRetryInternalAsync(
            HttpStatusCode?statusCode,
            SubStatusCodes?subStatusCode,
            CancellationToken cancellationToken)
        {
            if (statusCode == HttpStatusCode.Gone)
            {
                this.retriesOn410++;

                if (this.retriesOn410 > MaxRetryOn410)
                {
                    return(ShouldRetryResult.NoRetry());
                }

                if (subStatusCode == SubStatusCodes.PartitionKeyRangeGone ||
                    subStatusCode == SubStatusCodes.CompletingSplit ||
                    subStatusCode == SubStatusCodes.CompletingPartitionMigration)
                {
                    PartitionKeyRangeCache partitionKeyRangeCache = await this.container.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync(NoOpTrace.Singleton);

                    string containerRid = await this.container.GetCachedRIDAsync(
                        forceRefresh : false,
                        NoOpTrace.Singleton,
                        cancellationToken : cancellationToken);

                    await partitionKeyRangeCache.TryGetOverlappingRangesAsync(
                        containerRid,
                        FeedRangeEpk.FullRange.Range,
                        NoOpTrace.Singleton,
                        forceRefresh : true);

                    return(ShouldRetryResult.RetryAfter(TimeSpan.Zero));
                }

                if (subStatusCode == SubStatusCodes.NameCacheIsStale)
                {
                    return(ShouldRetryResult.RetryAfter(TimeSpan.Zero));
                }
            }

            // Batch API can return 413 which means the response is bigger than 4Mb.
            // Operations that exceed the 4Mb limit are returned as 413/3402, while the operations within the 4Mb limit will be 200
            if (statusCode == HttpStatusCode.RequestEntityTooLarge &&
                (int)subStatusCode == SubstatusCodeBatchResponseSizeExceeded)
            {
                return(ShouldRetryResult.RetryAfter(TimeSpan.Zero));
            }

            return(null);
        }
Ejemplo n.º 6
0
        public async Task GetChangeFeedTokensAsyncReturnsOnePerPartitionKeyRange()
        {
            // Setting mock to have 3 ranges, to generate 3 tokens
            MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient();

            using CosmosClient client = MockCosmosUtil.CreateMockCosmosClient();
            Mock <CosmosClientContext> mockContext = new Mock <CosmosClientContext>();

            mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration());
            mockContext.Setup(x => x.DocumentClient).Returns(documentClient);
            mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer);
            mockContext.Setup(x => x.Client).Returns(client);
            mockContext.Setup(x => x.CreateLink(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).Returns(UriFactory.CreateDocumentCollectionUri("test", "test").OriginalString);

            DatabaseInternal     db        = new DatabaseInlineCore(mockContext.Object, "test");
            ContainerInternal    container = new ContainerInlineCore(mockContext.Object, db, "test");
            IEnumerable <string> tokens    = await container.GetChangeFeedTokensAsync();

            Assert.AreEqual(3, tokens.Count());

            PartitionKeyRangeCache pkRangeCache = await documentClient.GetPartitionKeyRangeCacheAsync();

            foreach (string token in tokens)
            {
                // Validate that each token represents a StandByFeedContinuationToken with a single Range
                List <CompositeContinuationToken> deserialized = JsonConvert.DeserializeObject <List <CompositeContinuationToken> >(token);
                Assert.AreEqual(1, deserialized.Count);
                CompositeContinuationToken compositeToken = deserialized[0];

                IReadOnlyList <Documents.PartitionKeyRange> rangesForTheToken = await pkRangeCache.TryGetOverlappingRangesAsync("", compositeToken.Range);

                // Token represents one range
                Assert.AreEqual(1, rangesForTheToken.Count);
                Assert.AreEqual(rangesForTheToken[0].MinInclusive, compositeToken.Range.Min);
                Assert.AreEqual(rangesForTheToken[0].MaxExclusive, compositeToken.Range.Max);
            }
        }
Ejemplo n.º 7
0
        public async Task <IReadOnlyList <FeedRange> > GetFeedRangesAsync(
            CosmosDiagnosticsContext diagnosticsContext,
            ITrace trace,
            CancellationToken cancellationToken = default)
        {
            PartitionKeyRangeCache partitionKeyRangeCache = await this.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync();

            string containerRId;

            using (diagnosticsContext.CreateScope(nameof(GetCachedRIDAsync)))
            {
                containerRId = await this.GetCachedRIDAsync(
                    forceRefresh : false,
                    cancellationToken);
            }

            IReadOnlyList <PartitionKeyRange> partitionKeyRanges;

            using (diagnosticsContext.CreateScope(nameof(partitionKeyRangeCache.TryGetOverlappingRangesAsync)))
            {
                partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync(
                    containerRId,
                    ContainerCore.allRanges,
                    forceRefresh : true);
            }

            if (partitionKeyRanges == null)
            {
                string refreshedContainerRId;
                using (diagnosticsContext.CreateScope("GetRIDAsyncForceRefresh"))
                {
                    refreshedContainerRId = await this.GetCachedRIDAsync(
                        forceRefresh : true,
                        cancellationToken);
                }

                if (string.Equals(containerRId, refreshedContainerRId))
                {
                    throw CosmosExceptionFactory.CreateInternalServerErrorException(
                              $"Container rid {containerRId} did not have a partition key range after refresh",
                              diagnosticsContext: diagnosticsContext);
                }

                using (diagnosticsContext.CreateScope(nameof(partitionKeyRangeCache.TryGetOverlappingRangesAsync)))
                {
                    partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync(
                        containerRId,
                        ContainerCore.allRanges,
                        forceRefresh : true);
                }

                if (partitionKeyRanges == null)
                {
                    throw CosmosExceptionFactory.CreateInternalServerErrorException(
                              $"Container rid {containerRId} returned partitionKeyRanges null after Container RID refresh",
                              diagnosticsContext: diagnosticsContext);
                }
            }

            List <FeedRange> feedTokens = new List <FeedRange>(partitionKeyRanges.Count);

            foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges)
            {
                feedTokens.Add(new FeedRangeEpk(partitionKeyRange.ToRange()));
            }

            return(feedTokens);
        }
Ejemplo n.º 8
0
        async Task <IEnumerable <string> > GetPartitionKeyRangesAsync(
            FeedToken feedToken,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (feedToken is FeedTokenEPKRange feedTokenEPKRange)
            {
                PartitionKeyRangeCache partitionKeyRangeCache = await this.ClientContext.DocumentClient.GetPartitionKeyRangeCacheAsync();

                string containerRId = await this.GetRIDAsync(cancellationToken);

                IReadOnlyList <Documents.PartitionKeyRange> partitionKeyRanges = await partitionKeyRangeCache.TryGetOverlappingRangesAsync(containerRId, feedTokenEPKRange.CompleteRange, forceRefresh : false);

                return(partitionKeyRanges.Select(partitionKeyRange => partitionKeyRange.Id));
            }

            if (feedToken is FeedTokenPartitionKeyRange feedTokenPartitionKeyRange)
            {
                if (feedTokenPartitionKeyRange.FeedTokenEPKRange != null)
                {
                    return(await this.GetPartitionKeyRangesAsync(feedTokenPartitionKeyRange.FeedTokenEPKRange, cancellationToken));
                }

                return(new List <string>()
                {
                    feedTokenPartitionKeyRange.PartitionKeyRangeId
                });
            }

            if (feedToken is FeedTokenPartitionKey feedTokenPartitionKey)
            {
                CollectionRoutingMap collectionRoutingMap = await this.GetRoutingMapAsync(cancellationToken);

                PartitionKeyDefinition partitionKeyDefinition = await this.GetPartitionKeyDefinitionAsync(cancellationToken);

                PartitionKeyInternal partitionKeyInternal = feedTokenPartitionKey.PartitionKey.InternalKey;
                string effectivePartitionKeyString        = partitionKeyInternal.GetEffectivePartitionKeyString(partitionKeyDefinition);
                string partitionKeyRangeId = collectionRoutingMap.GetRangeByEffectivePartitionKey(effectivePartitionKeyString).Id;
                return(new List <string>()
                {
                    partitionKeyRangeId
                });
            }

            throw new ArgumentException(nameof(feedToken), ClientResources.FeedToken_UnrecognizedFeedToken);
        }