コード例 #1
0
        public static TryCatch <PartitionMapping <PartitionedToken> > MonadicGetPartitionMapping <PartitionedToken>(
            IReadOnlyList <FeedRangeEpk> feedRanges,
            IReadOnlyList <PartitionedToken> tokens)
            where PartitionedToken : IPartitionedToken
        {
            if (feedRanges == null)
            {
                throw new ArgumentNullException(nameof(feedRanges));
            }

            if (tokens == null)
            {
                throw new ArgumentNullException(nameof(tokens));
            }

            if (feedRanges.Count < 1)
            {
                throw new ArgumentException(nameof(feedRanges));
            }

            if (tokens.Count < 1)
            {
                throw new ArgumentException(nameof(feedRanges));
            }

            List <FeedRangeEpk> mergedFeedRanges = MergeRangesWherePossible(feedRanges);
            List <(FeedRangeEpk, PartitionedToken)> splitRangesAndTokens = SplitRangesBasedOffContinuationToken(mergedFeedRanges, tokens);
            FeedRangeEpk targetFeedRange = GetTargetFeedRange(tokens);

            return(MonadicConstructPartitionMapping(
                       splitRangesAndTokens,
                       tokens,
                       targetFeedRange));
        }
コード例 #2
0
        public void FeedRangeEPK_Range()
        {
            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("AA", "BB", true, false);
            FeedRangeEpk feedRangeEPK = new FeedRangeEpk(range);

            Assert.AreEqual(range, feedRangeEPK.Range);
        }
コード例 #3
0
        public void TestMatchRangesTocontinuationTokens_OneToNone()
        {
            FeedRangeEpk partitionKeyRange = new FeedRangeEpk(
                new Documents.Routing.Range <string>(
                    min: string.Empty,
                    max: "A",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            ParallelContinuationToken token = new ParallelContinuationToken(
                token: "asdf",
                range: new Documents.Routing.Range <string>(
                    min: "B",
                    max: "C",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMapping = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
                { partitionKeyRange, null },
            };

            ContinuationResumeLogicTests.RunMatchRangesToContinuationTokens(
                expectedMapping,
                new FeedRangeEpk[] { partitionKeyRange },
                new ParallelContinuationToken[] { token });
        }
コード例 #4
0
        public async Task <TryCatch <QueryPage> > VisitAsync(
            FeedRangeEpk feedRange,
            Arguments argument,
            CancellationToken cancellationToken)
        {
            // Check to see if it lines up exactly with one physical partition
            TryCatch <List <PartitionKeyRange> > tryGetFeedRanges = await this.documentContainer.MonadicGetChildRangeAsync(
                new PartitionKeyRange()
            {
                MinInclusive = feedRange.Range.Min,
                MaxExclusive = feedRange.Range.Max,
            },
                cancellationToken);

            if (tryGetFeedRanges.Failed)
            {
                return(TryCatch <QueryPage> .FromException(tryGetFeedRanges.Exception));
            }

            List <PartitionKeyRange> feedRanges = tryGetFeedRanges.Result;

            if (feedRanges.Count != 1)
            {
                // Simulate a split exception, since we don't have a partition key range id to route to.
                CosmosException goneException = new CosmosException(
                    message: $"Epk Range: {feedRange.Range} is gone.",
                    statusCode: System.Net.HttpStatusCode.Gone,
                    subStatusCode: (int)SubStatusCodes.PartitionKeyRangeGone,
                    activityId: Guid.NewGuid().ToString(),
                    requestCharge: default);
        public void ReadFeedIteratorCore_Create_Default()
        {
            FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(Mock.Of <ContainerInternal>(), null, null, null);
            FeedRangeEpk          defaultRange      = feedTokenIterator.FeedRangeInternal as FeedRangeEpk;

            Assert.AreEqual(FeedRangeEpk.FullRange.Range.Min, defaultRange.Range.Min);
            Assert.AreEqual(FeedRangeEpk.FullRange.Range.Max, defaultRange.Range.Max);
            Assert.IsNull(feedTokenIterator.FeedRangeContinuation);
        }
 public void Visit(FeedRangeEpk feedRange, RequestMessage requestMessage)
 {
     // In case EPK has already been set by compute
     if (!requestMessage.Properties.ContainsKey(HandlerConstants.StartEpkString))
     {
         requestMessage.Properties[HandlerConstants.StartEpkString] = feedRange.Range.Min;
         requestMessage.Properties[HandlerConstants.EndEpkString]   = feedRange.Range.Max;
     }
 }
コード例 #7
0
        public async Task FeedRangeEPK_GetEffectiveRangesAsync()
        {
            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("AA", "BB", true, false);
            FeedRangeEpk feedRangeEPK = new FeedRangeEpk(range);
            List <Documents.Routing.Range <string> > ranges = await feedRangeEPK.GetEffectiveRangesAsync(Mock.Of <IRoutingMapProvider>(), null, null);

            Assert.AreEqual(1, ranges.Count);
            Assert.AreEqual(range, ranges[0]);
        }
        public void ReadFeedIteratorCore_Create_WithRange()
        {
            Documents.Routing.Range <string> range  = new Documents.Routing.Range <string>("A", "B", true, false);
            FeedRangeEpk          feedRangeEPK      = new FeedRangeEpk(range);
            FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(Mock.Of <ContainerInternal>(), feedRangeEPK, null, null);

            Assert.AreEqual(feedRangeEPK, feedTokenIterator.FeedRangeInternal);
            Assert.IsNull(feedTokenIterator.FeedRangeContinuation);
        }
コード例 #9
0
        public void FeedRangeEPK_ToJsonFromJson()
        {
            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("AA", "BB", true, false);
            FeedRangeEpk feedRangeEPK             = new FeedRangeEpk(range);
            string       representation           = feedRangeEPK.ToJsonString();
            FeedRangeEpk feedRangeEPKDeserialized = Cosmos.FeedRange.FromJsonString(representation) as FeedRangeEpk;

            Assert.IsNotNull(feedRangeEPKDeserialized);
            Assert.AreEqual(feedRangeEPK.Range.Min, feedRangeEPKDeserialized.Range.Min);
            Assert.AreEqual(feedRangeEPK.Range.Max, feedRangeEPKDeserialized.Range.Max);
        }
コード例 #10
0
        public void FeedRangeEPK_RequestVisitor()
        {
            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("AA", "BB", true, false);
            FeedRangeEpk   feedRange      = new FeedRangeEpk(range);
            RequestMessage requestMessage = new RequestMessage();

            feedRange.Accept(FeedRangeRequestMessagePopulatorVisitor.Singleton, requestMessage);
            Assert.AreEqual(2, requestMessage.Properties.Count);
            Assert.AreEqual("AA", requestMessage.Properties[HandlerConstants.StartEpkString]);
            Assert.AreEqual("BB", requestMessage.Properties[HandlerConstants.EndEpkString]);
        }
コード例 #11
0
        public void ReadFeedIteratorCore_Create_WithContinuation()
        {
            string continuation = Guid.NewGuid().ToString();
            FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(Mock.Of <ContainerInternal>(), null, continuation, null);
            FeedRangeEpk          defaultRange      = feedTokenIterator.FeedRangeInternal as FeedRangeEpk;

            Assert.AreEqual(FeedRangeEpk.FullRange.Range.Min, defaultRange.Range.Min);
            Assert.AreEqual(FeedRangeEpk.FullRange.Range.Max, defaultRange.Range.Max);
            Assert.IsNotNull(feedTokenIterator.FeedRangeContinuation);
            Assert.AreEqual(continuation, feedTokenIterator.FeedRangeContinuation.GetContinuation());
        }
コード例 #12
0
        public void TestTryGetInitializationInfo_ResumeRightPartition()
        {
            FeedRangeEpk pkRange1 = new FeedRangeEpk(
                new Documents.Routing.Range <string>(
                    min: string.Empty,
                    max: "A",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            FeedRangeEpk pkRange2 = new FeedRangeEpk(
                new Documents.Routing.Range <string>(
                    min: "A",
                    max: "B",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            FeedRangeEpk pkRange3 = new FeedRangeEpk(
                new Documents.Routing.Range <string>(
                    min: "B",
                    max: "C",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            ParallelContinuationToken token = new ParallelContinuationToken(
                token: "asdf",
                range: new Documents.Routing.Range <string>(
                    min: "B",
                    max: "C",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMappingLeftPartitions = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
                { pkRange1, null },
                { pkRange2, null },
            };

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMappingTargetPartition = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
                { pkRange3, token },
            };

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMappingRightPartitions = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
            };

            RunTryGetInitializationInfo(
                expectedMappingLeftPartitions,
                expectedMappingTargetPartition,
                expectedMappingRightPartitions,
                new FeedRangeEpk[] { pkRange1, pkRange2, pkRange3 },
                new IPartitionedToken[] { token });
        }
コード例 #13
0
        public void EffectivePartitionKeyRange()
        {
            Microsoft.Azure.Documents.Routing.Range <string> range = new Microsoft.Azure.Documents.Routing.Range <string>(
                min: "A",
                max: "B",
                isMinInclusive: true,
                isMaxInclusive: false);

            FeedRangeInternal feedRange = new FeedRangeEpk(range);

            AssertRoundTrip(feedRange);
        }
コード例 #14
0
        public void ResumeOnMultipleTokens()
        {
            FeedRangeEpk range = Range(min: "A", max: "F");
            ParallelContinuationToken token1 = Token(min: "A", max: "C");
            ParallelContinuationToken token2 = Token(min: "C", max: "E");

            RunTryGetInitializationInfo(
                Mapping(),
                Mapping((Range(min: "A", max: "C"), token1)),
                Mapping((Range(min: "C", max: "E"), token2), (Range(min: "E", max: "F"), null)),
                new FeedRangeEpk[] { range, },
                new IPartitionedToken[] { token1, token2 });
        }
コード例 #15
0
        public async Task ReadFeedIteratorCore_WithNoInitialState_ReadNextAsync()
        {
            string          continuation    = "TBD";
            ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK);

            responseMessage.Headers.ContinuationToken = continuation;
            responseMessage.Headers[Documents.HttpConstants.HttpHeaders.ItemCount] = "1";
            responseMessage.Content = new MemoryStream(Encoding.UTF8.GetBytes("{}"));

            MultiRangeMockDocumentClient documentClient = new MultiRangeMockDocumentClient();

            Mock <CosmosClientContext> cosmosClientContext = new Mock <CosmosClientContext>();

            cosmosClientContext.Setup(c => c.ClientOptions).Returns(new CosmosClientOptions());
            cosmosClientContext.Setup(c => c.DocumentClient).Returns(documentClient);
            cosmosClientContext
            .Setup(c => c.ProcessResourceOperationStreamAsync(
                       It.IsAny <string>(),
                       It.Is <Documents.ResourceType>(rt => rt == Documents.ResourceType.Document),
                       It.IsAny <Documents.OperationType>(),
                       It.IsAny <RequestOptions>(),
                       It.IsAny <ContainerInternal>(),
                       It.IsAny <PartitionKey?>(),
                       It.IsAny <Stream>(),
                       It.IsAny <Action <RequestMessage> >(),
                       It.IsAny <CosmosDiagnosticsContext>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.FromResult(responseMessage));

            ContainerInternal containerCore = Mock.Of <ContainerInternal>();

            Mock.Get(containerCore)
            .Setup(c => c.ClientContext)
            .Returns(cosmosClientContext.Object);
            Mock.Get(containerCore)
            .Setup(c => c.GetRIDAsync(It.IsAny <CancellationToken>()))
            .ReturnsAsync(Guid.NewGuid().ToString());

            FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(containerCore, null, null, new QueryRequestOptions());
            ResponseMessage       response          = await feedTokenIterator.ReadNextAsync();

            Assert.IsTrue(FeedRangeContinuation.TryParse(response.ContinuationToken, out FeedRangeContinuation parsedToken));
            FeedRangeCompositeContinuation feedRangeCompositeContinuation = parsedToken as FeedRangeCompositeContinuation;
            FeedRangeEpk feedTokenEPKRange = feedRangeCompositeContinuation.FeedRange as FeedRangeEpk;

            // Assert that a FeedToken for the entire range is used
            Assert.AreEqual(Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, feedTokenEPKRange.Range.Min);
            Assert.AreEqual(Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, feedTokenEPKRange.Range.Max);
            Assert.AreEqual(continuation, feedRangeCompositeContinuation.CompositeContinuationTokens.Peek().Token);
            Assert.IsFalse(feedRangeCompositeContinuation.IsDone);
        }
コード例 #16
0
        public void ResumeRightPartition()
        {
            FeedRangeEpk range1             = Range(min: string.Empty, max: "A");
            FeedRangeEpk range2             = Range(min: "A", max: "B");
            FeedRangeEpk range3             = Range(min: "B", max: "C");
            ParallelContinuationToken token = Token(min: "B", max: "C");

            RunTryGetInitializationInfo(
                Mapping((CombineRanges(range1, range2), null)),
                Mapping((range3, token)),
                Mapping(),
                new FeedRangeEpk[] { range1, range2, range3 },
                new IPartitionedToken[] { token });
        }
コード例 #17
0
        public void FeedRangeCompositeContinuation_TryParse()
        {
            const string containerRid = "containerRid";
            List <Documents.Routing.Range <string> > keyRanges = new List <Documents.Routing.Range <string> >()
            {
                new Documents.Routing.Range <string>("A", "B", true, false),
                new Documents.Routing.Range <string>("D", "E", true, false),
            };
            FeedRangeInternal feedRangeInternal  = new FeedRangeEpk(new Documents.Routing.Range <string>("A", "E", true, false));
            FeedRangeCompositeContinuation token = new FeedRangeCompositeContinuation(containerRid, feedRangeInternal, keyRanges);

            Assert.IsTrue(FeedRangeContinuation.TryParse(token.ToString(), out _));
            Assert.IsFalse(FeedRangeContinuation.TryParse("whatever", out _));
        }
コード例 #18
0
        public void ReadFeedIteratorCore_Create_WithFeedContinuation()
        {
            string       continuation = Guid.NewGuid().ToString();
            FeedRangeEpk feedRangeEPK = FeedRangeEpk.FullRange;
            FeedRangeCompositeContinuation feedRangeSimpleContinuation = new FeedRangeCompositeContinuation(Guid.NewGuid().ToString(), feedRangeEPK, new List <Documents.Routing.Range <string> >()
            {
                feedRangeEPK.Range
            }, continuation);
            FeedRangeIteratorCore feedTokenIterator = FeedRangeIteratorCore.Create(Mock.Of <ContainerInternal>(), null, feedRangeSimpleContinuation.ToString(), null);
            FeedRangeEpk          defaultRange      = feedTokenIterator.FeedRangeInternal as FeedRangeEpk;

            Assert.AreEqual(FeedRangeEpk.FullRange.Range.Min, defaultRange.Range.Min);
            Assert.AreEqual(FeedRangeEpk.FullRange.Range.Max, defaultRange.Range.Max);
            Assert.IsNotNull(feedTokenIterator.FeedRangeContinuation);
            Assert.AreEqual(continuation, feedTokenIterator.FeedRangeContinuation.GetContinuation());
        }
コード例 #19
0
        public void ResumeOnSplit_LogicalParition()
        {
            // Suppose the partition spans epk range A to E
            // And the user send a query with partition key that hashes to C
            // The the token will look like:
            ParallelContinuationToken token = Token(min: "A", "E");

            // Now suppose there is a split that creates two partitions A to B and B to E
            // Now C will map to the partition that goes from B to E
            FeedRangeEpk range = Range(min: "B", max: "E");

            RunTryGetInitializationInfo(
                Mapping(),
                Mapping((range, token)),
                Mapping(),
                new FeedRangeEpk[] { range },
                new IPartitionedToken[] { token });
        }
コード例 #20
0
        public async Task FeedRangeEPK_GetPartitionKeyRangesAsync()
        {
            Documents.Routing.Range <string> range             = new Documents.Routing.Range <string>("AA", "BB", true, false);
            Documents.PartitionKeyRange      partitionKeyRange = new Documents.PartitionKeyRange()
            {
                Id = Guid.NewGuid().ToString(), MinInclusive = range.Min, MaxExclusive = range.Max
            };
            FeedRangePartitionKeyRange feedRangePartitionKeyRange = new FeedRangePartitionKeyRange(partitionKeyRange.Id);
            IRoutingMapProvider        routingProvider            = Mock.Of <IRoutingMapProvider>();

            Mock.Get(routingProvider)
            .Setup(f => f.TryGetOverlappingRangesAsync(It.IsAny <string>(), It.Is <Documents.Routing.Range <string> >(s => s == range), It.IsAny <ITrace>(), It.IsAny <bool>()))
            .ReturnsAsync(new List <Documents.PartitionKeyRange>()
            {
                partitionKeyRange
            });

            FeedRangeEpk         FeedRangeEpk = new FeedRangeEpk(range);
            IEnumerable <string> pkRanges     = await FeedRangeEpk.GetPartitionKeyRangesAsync(routingProvider, null, null, default, NoOpTrace.Singleton);
コード例 #21
0
        public async Task FeedRange_EPK_Serialization()
        {
            string           continuation   = "TBD";
            string           containerRid   = Guid.NewGuid().ToString();
            List <FeedRange> ranges         = (await this.Container.GetFeedRangesAsync()).ToList();
            List <string>    serializations = new List <string>();
            List <FeedRangeCompositeContinuation> tokens = new List <FeedRangeCompositeContinuation>();

            foreach (FeedRange range in ranges)
            {
                FeedRangeEpk feedRangeEPK = range as FeedRangeEpk;
                FeedRangeCompositeContinuation feedRangeCompositeContinuation = new FeedRangeCompositeContinuation(containerRid, feedRangeEPK, new List <Documents.Routing.Range <string> >()
                {
                    feedRangeEPK.Range
                }, continuation);
                tokens.Add(feedRangeCompositeContinuation);
                serializations.Add(feedRangeCompositeContinuation.ToString());
            }

            List <FeedRangeContinuation> deserialized = new List <FeedRangeContinuation>();

            foreach (string serialized in serializations)
            {
                Assert.IsTrue(FeedRangeContinuation.TryParse(serialized, out FeedRangeContinuation token));
                deserialized.Add(token);
            }

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

            for (int i = 0; i < tokens.Count; i++)
            {
                FeedRangeCompositeContinuation originalToken     = tokens[i] as FeedRangeCompositeContinuation;
                FeedRangeCompositeContinuation deserializedToken = deserialized[i] as FeedRangeCompositeContinuation;
                Assert.AreEqual(originalToken.GetContinuation(), deserializedToken.GetContinuation());
                Assert.AreEqual(originalToken.ContainerRid, deserializedToken.ContainerRid);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Count, deserializedToken.CompositeContinuationTokens.Count);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Token, deserializedToken.CompositeContinuationTokens.Peek().Token);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.Min, deserializedToken.CompositeContinuationTokens.Peek().Range.Min);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.Max, deserializedToken.CompositeContinuationTokens.Peek().Range.Max);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.IsMinInclusive, deserializedToken.CompositeContinuationTokens.Peek().Range.IsMinInclusive);
                Assert.AreEqual(originalToken.CompositeContinuationTokens.Peek().Range.IsMaxInclusive, deserializedToken.CompositeContinuationTokens.Peek().Range.IsMaxInclusive);
            }
        }
コード例 #22
0
        public void TestTryGetInitializationInfo_ResumeLogicalParition()
        {
            // Suppose the partition spans epk range A to E
            // And the user send a query with partition key that hashes to C
            // The the token will look like:
            ParallelContinuationToken token = new ParallelContinuationToken(
                token: "asdf",
                range: new Documents.Routing.Range <string>(
                    min: "A",
                    max: "E",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            // Now suppose there is a split that creates two partitions A to B and B to E
            // Now C will map to the partition that goes from B to E
            FeedRangeEpk pkRange = new FeedRangeEpk(
                new Documents.Routing.Range <string>(
                    min: "B",
                    max: "E",
                    isMinInclusive: true,
                    isMaxInclusive: false));

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMappingLeftPartitions = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
            };

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMappingTargetPartition = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
                { pkRange, token },
            };

            IReadOnlyDictionary <FeedRangeEpk, IPartitionedToken> expectedMappingRightPartitions = new Dictionary <FeedRangeEpk, IPartitionedToken>()
            {
            };

            RunTryGetInitializationInfo(
                expectedMappingLeftPartitions,
                expectedMappingTargetPartition,
                expectedMappingRightPartitions,
                new FeedRangeEpk[] { pkRange },
                new IPartitionedToken[] { token });
        }
コード例 #23
0
        public override Task <DocumentServiceLease> CreateLeaseIfNotExistAsync(
            FeedRangeEpk feedRange,
            string continuationToken)
        {
            if (feedRange == null)
            {
                throw new ArgumentNullException(nameof(feedRange));
            }

            string leaseToken = $"{feedRange.Range.Min}-{feedRange.Range.Max}";
            DocumentServiceLeaseCoreEpk documentServiceLease = new DocumentServiceLeaseCoreEpk
            {
                LeaseId           = leaseToken,
                LeaseToken        = leaseToken,
                ContinuationToken = continuationToken,
                FeedRange         = feedRange
            };

            return(this.TryCreateDocumentServiceLeaseAsync(documentServiceLease));
        }
コード例 #24
0
        public void ResumeOnAMerge()
        {
            // Suppose that we read from range 1
            FeedRangeEpk range1 = Range(min: string.Empty, max: "A");

            // Then Range 1 Merged with Range 2
            FeedRangeEpk range2 = Range(min: "A", max: "B");

            // And we have a continuation token for range 1
            ParallelContinuationToken token = Token(min: string.Empty, max: "A");

            // Then we should resume on range 1 with epk range filtering
            // and still have range 2 with null continuation.
            RunTryGetInitializationInfo(
                Mapping(),
                Mapping((range1, token)),
                Mapping((range2, null)),
                new FeedRangeEpk[] { CombineRanges(range1, range2) },
                new IPartitionedToken[] { token });
        }
        public async Task CreatesEPKBasedLease(int factoryType)
        {
            RequestOptionsFactory requestOptionsFactory = GetRequestOptionsFactory(factoryType);
            string continuation = Guid.NewGuid().ToString();
            DocumentServiceLeaseStoreManagerOptions options = new DocumentServiceLeaseStoreManagerOptions
            {
                HostName = Guid.NewGuid().ToString()
            };

            FeedRangeEpk feedRangeEpk = new FeedRangeEpk(new Documents.Routing.Range <string>("AA", "BB", true, false));

            Mock <DocumentServiceLeaseUpdater> mockUpdater = new Mock <DocumentServiceLeaseUpdater>();

            Mock <ContainerInternal> mockedContainer = new Mock <ContainerInternal>();

            mockedContainer.Setup(c => c.CreateItemStreamAsync(
                                      It.IsAny <Stream>(),
                                      It.IsAny <PartitionKey>(),
                                      It.IsAny <ItemRequestOptions>(),
                                      It.IsAny <CancellationToken>())).ReturnsAsync((Stream stream, PartitionKey partitionKey, ItemRequestOptions options, CancellationToken token) => new ResponseMessage(System.Net.HttpStatusCode.OK)
            {
                Content = stream
            });

            DocumentServiceLeaseManagerCosmos documentServiceLeaseManagerCosmos = new DocumentServiceLeaseManagerCosmos(
                Mock.Of <ContainerInternal>(),
                mockedContainer.Object,
                mockUpdater.Object,
                options,
                requestOptionsFactory);

            DocumentServiceLease afterAcquire = await documentServiceLeaseManagerCosmos.CreateLeaseIfNotExistAsync(feedRangeEpk, continuation);

            DocumentServiceLeaseCoreEpk epkBasedLease = (DocumentServiceLeaseCoreEpk)afterAcquire;

            Assert.IsNotNull(epkBasedLease);
            Assert.AreEqual(continuation, afterAcquire.ContinuationToken);
            Assert.AreEqual(feedRangeEpk.Range.Min, ((FeedRangeEpk)epkBasedLease.FeedRange).Range.Min);
            Assert.AreEqual(feedRangeEpk.Range.Max, ((FeedRangeEpk)epkBasedLease.FeedRange).Range.Max);
            ValidateRequestOptionsFactory(requestOptionsFactory, epkBasedLease);
        }
コード例 #26
0
        /// <summary>
        /// Matches ranges to their corresponding continuation token.
        /// Note that most ranges don't have a corresponding continuation token, so their value will be set to null.
        /// Also note that in the event of a split two or more ranges will match to the same continuation token.
        /// </summary>
        /// <typeparam name="PartitionedToken">The type of token we are matching with.</typeparam>
        /// <param name="partitionKeyRanges">The partition key ranges to match.</param>
        /// <param name="partitionedContinuationTokens">The continuation tokens to match with.</param>
        /// <returns>A dictionary of ranges matched with their continuation tokens.</returns>
        public static IReadOnlyDictionary <FeedRangeEpk, PartitionedToken> MatchRangesToContinuationTokens <PartitionedToken>(
            ReadOnlyMemory <FeedRangeEpk> partitionKeyRanges,
            IReadOnlyList <PartitionedToken> partitionedContinuationTokens)
            where PartitionedToken : IPartitionedToken
        {
            if (partitionedContinuationTokens == null)
            {
                throw new ArgumentNullException(nameof(partitionedContinuationTokens));
            }

            Dictionary <FeedRangeEpk, PartitionedToken> partitionKeyRangeToToken = new Dictionary <FeedRangeEpk, PartitionedToken>();
            ReadOnlySpan <FeedRangeEpk> partitionKeyRangeSpan = partitionKeyRanges.Span;

            for (int i = 0; i < partitionKeyRangeSpan.Length; i++)
            {
                FeedRangeEpk feedRange = partitionKeyRangeSpan[i];
                foreach (PartitionedToken partitionedToken in partitionedContinuationTokens)
                {
                    bool rightOfStart = (partitionedToken.Range.Min == string.Empty) ||
                                        ((feedRange.Range.Min != string.Empty) && (feedRange.Range.Min.CompareTo(partitionedToken.Range.Min) >= 0));
                    bool leftOfEnd = (partitionedToken.Range.Max == string.Empty) ||
                                     ((feedRange.Range.Max != string.Empty) && (feedRange.Range.Max.CompareTo(partitionedToken.Range.Max) <= 0));
                    // See if continuation token includes the range
                    if (rightOfStart && leftOfEnd)
                    {
                        partitionKeyRangeToToken[feedRange] = partitionedToken;
                        break;
                    }
                }

                if (!partitionKeyRangeToToken.ContainsKey(feedRange))
                {
                    // Could not find a matching token so just set it to null
                    partitionKeyRangeToToken[feedRange] = default;
                }
            }

            return(partitionKeyRangeToToken);
        }
コード例 #27
0
        public void ResumeOnAMerge_LogicalPartition()
        {
            // Suppose that we read from range 2 with a logical partiton key that hashes to D
            FeedRangeEpk range2 = Range(min: "C", max: "E");

            // Then Range 1
            FeedRangeEpk range1 = Range(min: "A", max: "C");

            // and Range 3 merge with range 2
            FeedRangeEpk range3 = Range(min: "E", max: "G");

            // And we have a continuation token for range 2
            ParallelContinuationToken token = Token(min: "C", max: "E");

            // Then we should resume on range 2 with epk range filtering
            // and still have range 1 and 3 with null continuation (but, since there is a logical partition key it won't match any results).
            RunTryGetInitializationInfo(
                Mapping((range1, null)),
                Mapping((range2, token)),
                Mapping((range3, null)),
                new FeedRangeEpk[] { CombineRanges(CombineRanges(range1, range2), range3) },
                new IPartitionedToken[] { token });
        }
コード例 #28
0
        public override Task <DocumentServiceLease> CreateLeaseIfNotExistAsync(
            FeedRangeEpk feedRange,
            string continuationToken)
        {
            if (feedRange == null)
            {
                throw new ArgumentNullException(nameof(feedRange));
            }

            string leaseToken = $"{feedRange.Range.Min}-{feedRange.Range.Max}";
            string leaseDocId = this.GetDocumentId(leaseToken);
            DocumentServiceLeaseCoreEpk documentServiceLease = new DocumentServiceLeaseCoreEpk
            {
                LeaseId           = leaseDocId,
                LeaseToken        = leaseToken,
                ContinuationToken = continuationToken,
                FeedRange         = feedRange
            };

            this.requestOptionsFactory.AddPartitionKeyIfNeeded((string pk) => documentServiceLease.LeasePartitionKey = pk, Guid.NewGuid().ToString());

            return(this.TryCreateDocumentServiceLeaseAsync(documentServiceLease));
        }
コード例 #29
0
        public async Task FeedRangeEPK_GetPartitionKeyRangesAsync()
        {
            Documents.Routing.Range <string> range             = new Documents.Routing.Range <string>("AA", "BB", true, false);
            Documents.PartitionKeyRange      partitionKeyRange = new Documents.PartitionKeyRange()
            {
                Id = Guid.NewGuid().ToString(), MinInclusive = range.Min, MaxExclusive = range.Max
            };
            FeedRangePartitionKeyRange feedRangePartitionKeyRange = new FeedRangePartitionKeyRange(partitionKeyRange.Id);
            IRoutingMapProvider        routingProvider            = Mock.Of <IRoutingMapProvider>();

            Mock.Get(routingProvider)
            .Setup(f => f.TryGetOverlappingRangesAsync(It.IsAny <string>(), It.Is <Documents.Routing.Range <string> >(s => s == range), It.IsAny <bool>()))
            .ReturnsAsync(new List <Documents.PartitionKeyRange>()
            {
                partitionKeyRange
            });

            FeedRangeEpk         feedRangeEPK = new FeedRangeEpk(range);
            IEnumerable <string> pkRanges     = await feedRangeEPK.GetPartitionKeyRangesAsync(routingProvider, null, null, default(CancellationToken));

            Assert.AreEqual(1, pkRanges.Count());
            Assert.AreEqual(partitionKeyRange.Id, pkRanges.First());
        }
コード例 #30
0
        public async Task ShouldUseFeedRangeEpk()
        {
            int      itemCount = 5;
            string   pkRangeId = "0";
            DateTime startTime = DateTime.UtcNow;

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("AA", "BB", true, false);
            FeedRangeEpk feedRange = new FeedRangeEpk(range);
            DocumentServiceLeaseCoreEpk documentServiceLeaseCore = new DocumentServiceLeaseCoreEpk()
            {
                LeaseToken = pkRangeId,
                FeedRange  = feedRange
            };

            Mock <ContainerInternal>   containerMock = new Mock <ContainerInternal>();
            Mock <CosmosClientContext> mockContext   = new Mock <CosmosClientContext>();

            mockContext.Setup(c => c.ProcessResourceOperationStreamAsync(
                                  It.IsAny <string>(),
                                  It.Is <Documents.ResourceType>(rt => rt == Documents.ResourceType.Document),
                                  It.Is <Documents.OperationType>(rt => rt == Documents.OperationType.ReadFeed),
                                  It.Is <ChangeFeedRequestOptions>(cfo => cfo.PageSizeHint == itemCount),
                                  It.Is <ContainerInternal>(o => o == containerMock.Object),
                                  It.Is <FeedRange>(fr => fr is FeedRangeEpk),
                                  It.IsAny <Stream>(),
                                  It.IsAny <Action <RequestMessage> >(),
                                  It.IsAny <CosmosDiagnosticsContext>(),
                                  It.IsAny <ITrace>(),
                                  It.IsAny <CancellationToken>()
                                  )
                              ).ReturnsAsync(new ResponseMessage(System.Net.HttpStatusCode.OK));
            containerMock.Setup(c => c.ClientContext).Returns(mockContext.Object);
            containerMock.Setup(c => c.LinkUri).Returns("http://localhot");
            MockDocumentClient mockDocumentClient = new MockDocumentClient();

            mockContext.Setup(c => c.DocumentClient).Returns(mockDocumentClient);

            ChangeFeedPartitionKeyResultSetIteratorCore iterator = ChangeFeedPartitionKeyResultSetIteratorCore.Create(
                lease: documentServiceLeaseCore,
                continuationToken: null,
                maxItemCount: itemCount,
                container: containerMock.Object,
                startTime: startTime,
                startFromBeginning: false);

            ResponseMessage response = await iterator.ReadNextAsync();

            Assert.AreEqual(System.Net.HttpStatusCode.OK, response.StatusCode);

            mockContext.Verify(c => c.ProcessResourceOperationStreamAsync(
                                   It.IsAny <string>(),
                                   It.Is <Documents.ResourceType>(rt => rt == Documents.ResourceType.Document),
                                   It.Is <Documents.OperationType>(rt => rt == Documents.OperationType.ReadFeed),
                                   It.Is <ChangeFeedRequestOptions>(cfo => cfo.PageSizeHint == itemCount),
                                   It.Is <ContainerInternal>(o => o == containerMock.Object),
                                   It.Is <FeedRange>(fr => fr is FeedRangeEpk),
                                   It.IsAny <Stream>(),
                                   It.IsAny <Action <RequestMessage> >(),
                                   It.IsAny <CosmosDiagnosticsContext>(),
                                   It.IsAny <ITrace>(),
                                   It.IsAny <CancellationToken>()
                                   ), Times.Once);
        }