public static FeedRangeInternal ReadJObject(
            JObject jObject,
            JsonSerializer serializer)
        {
            if (jObject.TryGetValue(FeedRangeInternalConverter.RangePropertyName, out JToken rangeJToken))
            {
                try
                {
                    Documents.Routing.Range <string> completeRange = (Documents.Routing.Range <string>)rangeJsonConverter.ReadJson(rangeJToken.CreateReader(), typeof(Documents.Routing.Range <string>), null, serializer);
                    return(new FeedRangeEpk(completeRange));
                }
                catch (JsonSerializationException)
                {
                    throw new JsonReaderException();
                }
            }

            if (jObject.TryGetValue(FeedRangeInternalConverter.PartitionKeyPropertyName, out JToken pkJToken))
            {
                if (!PartitionKey.TryParseJsonString(pkJToken.Value <string>(), out PartitionKey partitionKey))
                {
                    throw new JsonReaderException();
                }

                return(new FeedRangePartitionKey(partitionKey));
            }

            if (jObject.TryGetValue(FeedRangeInternalConverter.PartitionKeyRangeIdPropertyName, out JToken pkRangeJToken))
            {
                return(new FeedRangePartitionKeyRange(pkRangeJToken.Value <string>()));
            }

            throw new JsonReaderException();
        }
        public FeedTokenEPKRange(
            string containerRid,
            Documents.Routing.Range <string> completeRange,
            IReadOnlyList <CompositeContinuationToken> deserializedTokens)
            : this(containerRid)
        {
            if (deserializedTokens == null)
            {
                throw new ArgumentNullException(nameof(deserializedTokens));
            }

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

            if (deserializedTokens.Count == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(deserializedTokens));
            }

            this.CompleteRange = completeRange;

            foreach (CompositeContinuationToken token in deserializedTokens)
            {
                this.CompositeContinuationTokens.Enqueue(token);
            }

            this.currentToken = this.CompositeContinuationTokens.Peek();
        }
Exemple #3
0
        public async Task FeedRangePK_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
            };
            Documents.PartitionKeyDefinition partitionKeyDefinition = new Documents.PartitionKeyDefinition();
            partitionKeyDefinition.Paths.Add("/id");
            PartitionKey        partitionKey    = new PartitionKey("test");
            IRoutingMapProvider routingProvider = Mock.Of <IRoutingMapProvider>();

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

            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);
            IEnumerable <string>  pkRanges = await feedRangePartitionKey.GetPartitionKeyRangesAsync(routingProvider, null, partitionKeyDefinition, default(CancellationToken));

            Assert.AreEqual(1, pkRanges.Count());
            Assert.AreEqual(partitionKeyRange.Id, pkRanges.First());
        }
Exemple #4
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);
        }
Exemple #5
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 async Task HandlePartitionGoneAsync_EpkBasedLease_Merge()
        {
            string continuation = Guid.NewGuid().ToString();

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("AA", "EE", true, false);
            DocumentServiceLeaseCoreEpk      lease = new DocumentServiceLeaseCoreEpk()
            {
                LeaseToken        = "AA-BB",
                ContinuationToken = continuation,
                Owner             = Guid.NewGuid().ToString(),
                FeedRange         = new FeedRangeEpk(range)
            };

            Mock <Routing.PartitionKeyRangeCache> pkRangeCache = new Mock <Routing.PartitionKeyRangeCache>(
                Mock.Of <Documents.IAuthorizationTokenProvider>(),
                Mock.Of <Documents.IStoreModel>(),
                Mock.Of <Common.CollectionCache>());

            List <Documents.PartitionKeyRange> resultingRanges = new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    Id = "1", MinInclusive = "", MaxExclusive = "FF"
                },
            };

            pkRangeCache.Setup(p => p.TryGetOverlappingRangesAsync(
                                   It.IsAny <string>(),
                                   It.Is <Documents.Routing.Range <string> >(r => r.Min == range.Min && r.Max == range.Max),
                                   It.IsAny <ITrace>(),
                                   true))
            .ReturnsAsync(resultingRanges);

            Mock <DocumentServiceLeaseManager> leaseManager = new Mock <DocumentServiceLeaseManager>();

            PartitionSynchronizerCore partitionSynchronizerCore = new PartitionSynchronizerCore(
                Mock.Of <ContainerInternal>(),
                Mock.Of <DocumentServiceLeaseContainer>(),
                leaseManager.Object,
                1,
                pkRangeCache.Object,
                Guid.NewGuid().ToString());

            (IEnumerable <DocumentServiceLease> addedLeases, bool shouldDelete) = await partitionSynchronizerCore.HandlePartitionGoneAsync(lease);

            Assert.IsFalse(shouldDelete);

            Assert.AreEqual(lease, addedLeases.First());

            leaseManager.Verify(l => l.CreateLeaseIfNotExistAsync(
                                    It.IsAny <Documents.PartitionKeyRange>(),
                                    It.IsAny <string>()), Times.Never);

            leaseManager.Verify(l => l.CreateLeaseIfNotExistAsync(
                                    It.IsAny <FeedRangeEpk>(),
                                    It.IsAny <string>()), Times.Never);
        }
        public static TryCatch <CompositeContinuationToken> TryCreateFromCosmosElement(CosmosElement cosmosElement)
        {
            if (!(cosmosElement is CosmosObject cosmosObject))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is not an object: {cosmosElement}")));
            }

            if (!cosmosObject.TryGetValue(PropertyNames.Token, out CosmosElement rawToken))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{PropertyNames.Token}': {cosmosElement}")));
            }

            string token;

            if (rawToken is CosmosString rawTokenString)
            {
                token = rawTokenString.Value;
            }
            else
            {
                token = null;
            }

            if (!cosmosObject.TryGetValue(PropertyNames.Range, out CosmosObject rawRange))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{PropertyNames.Range}': {cosmosElement}")));
            }

            if (!rawRange.TryGetValue(PropertyNames.Min, out CosmosString rawMin))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{PropertyNames.Min}': {cosmosElement}")));
            }

            string min = rawMin.Value;

            if (!rawRange.TryGetValue(PropertyNames.Max, out CosmosString rawMax))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{PropertyNames.Max}': {cosmosElement}")));
            }

            string max = rawMax.Value;

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>(min, max, true, false);

            CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken()
            {
                Token = token,
                Range = range,
            };

            return(TryCatch <CompositeContinuationToken> .FromResult(compositeContinuationToken));
        }
Exemple #8
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);
        }
Exemple #9
0
        public FeedRangeEpk(Documents.Routing.Range <string> range)
        {
            if (range == null)
            {
                throw new ArgumentNullException(nameof(range));
            }

            this.Range = range;
        }
        public async Task HandlePartitionGoneAsync_PKRangeBasedLease_Merge()
        {
            string continuation = Guid.NewGuid().ToString();

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("", "BB", true, false);
            DocumentServiceLeaseCore         lease = new DocumentServiceLeaseCore()
            {
                LeaseToken        = "0",
                ContinuationToken = continuation,
                Owner             = Guid.NewGuid().ToString(),
                FeedRange         = new FeedRangeEpk(range)
            };

            Mock <Routing.PartitionKeyRangeCache> pkRangeCache = new Mock <Routing.PartitionKeyRangeCache>(
                Mock.Of <Documents.IAuthorizationTokenProvider>(),
                Mock.Of <Documents.IStoreModel>(),
                Mock.Of <Common.CollectionCache>());

            List <Documents.PartitionKeyRange> resultingRanges = new List <Documents.PartitionKeyRange>()
            {
                new Documents.PartitionKeyRange()
                {
                    Id = "2", MinInclusive = "", MaxExclusive = "FF"
                }
            };

            pkRangeCache.Setup(p => p.TryGetOverlappingRangesAsync(
                                   It.IsAny <string>(),
                                   It.Is <Documents.Routing.Range <string> >(r => r.Min == range.Min && r.Max == range.Max),
                                   It.IsAny <ITrace>(),
                                   It.Is <bool>(b => b == true)))
            .ReturnsAsync(resultingRanges);

            Mock <DocumentServiceLeaseManager> leaseManager = new Mock <DocumentServiceLeaseManager>();

            PartitionSynchronizerCore partitionSynchronizerCore = new PartitionSynchronizerCore(
                Mock.Of <ContainerInternal>(),
                Mock.Of <DocumentServiceLeaseContainer>(),
                leaseManager.Object,
                1,
                pkRangeCache.Object,
                Guid.NewGuid().ToString());

            await partitionSynchronizerCore.HandlePartitionGoneAsync(lease);

            leaseManager.Verify(l => l.CreateLeaseIfNotExistAsync(
                                    It.IsAny <Documents.PartitionKeyRange>(),
                                    It.IsAny <string>()), Times.Never);

            leaseManager.Verify(l => l.CreateLeaseIfNotExistAsync(
                                    It.IsAny <FeedRangeEpk>(),
                                    It.IsAny <string>()), Times.Once);

            leaseManager.Verify(l => l.CreateLeaseIfNotExistAsync(
                                    It.Is <FeedRangeEpk>(epKRange => epKRange.Range.Min == range.Min && epKRange.Range.Max == range.Max),
                                    It.Is <string>(c => c == continuation)), Times.Once);
        }
Exemple #11
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();
            FeedRangeVisitor feedRangeVisitor      = new FeedRangeVisitor(requestMessage);

            feedRange.Accept(feedRangeVisitor);
            Assert.AreEqual(0, requestMessage.Properties.Count);
        }
Exemple #12
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]);
        }
Exemple #13
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);
        }
Exemple #14
0
        public async Task StandByFeedIterator_EmptyBeginning()
        {
            int    totalCount        = 0;
            int    expectedDocuments = 5;
            string lastcontinuation  = string.Empty;

            Documents.Routing.Range <string> previousRange = null;
            Documents.Routing.Range <string> currentRange  = null;

            int pkRangesCount   = (await this.Container.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.Container.LinkUri)).Count;
            int visitedPkRanges = 0;

            ContainerCore itemsCore    = (ContainerCore)this.Container;
            FeedIterator  feedIterator = itemsCore.GetStandByFeedIterator();

            while (feedIterator.HasMoreResults)
            {
                using (ResponseMessage responseMessage =
                           await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    lastcontinuation = responseMessage.Headers.ContinuationToken;
                    Assert.AreEqual(responseMessage.ContinuationToken, responseMessage.Headers.ContinuationToken);
                    List <CompositeContinuationToken> deserializedToken = JsonConvert.DeserializeObject <List <CompositeContinuationToken> >(lastcontinuation);
                    currentRange = deserializedToken[0].Range;
                    if (responseMessage.IsSuccessStatusCode)
                    {
                        Collection <ToDoActivity> response = TestCommon.Serializer.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(responseMessage.Content).Data;
                        totalCount += response.Count;
                    }
                    else
                    {
                        if (visitedPkRanges == 0)
                        {
                            await this.CreateRandomItems(this.Container, expectedDocuments, randomPartitionKey : true);
                        }
                    }

                    if (visitedPkRanges == pkRangesCount && responseMessage.StatusCode == System.Net.HttpStatusCode.NotModified)
                    {
                        break;
                    }

                    if (!currentRange.Equals(previousRange))
                    {
                        visitedPkRanges++;
                    }

                    previousRange = currentRange;
                }
            }

            Assert.AreEqual(expectedDocuments, totalCount);
        }
Exemple #15
0
        public async Task FeedRangePK_GetEffectiveRangesAsync()
        {
            Documents.PartitionKeyDefinition partitionKeyDefinition = new Documents.PartitionKeyDefinition();
            partitionKeyDefinition.Paths.Add("/id");
            PartitionKey          partitionKey          = new PartitionKey("test");
            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);

            Documents.Routing.Range <string> range = Documents.Routing.Range <string> .GetPointRange(partitionKey.InternalKey.GetEffectivePartitionKeyString(partitionKeyDefinition));

            List <Documents.Routing.Range <string> > ranges = await feedRangePartitionKey.GetEffectiveRangesAsync(Mock.Of <IRoutingMapProvider>(), null, partitionKeyDefinition);

            Assert.AreEqual(1, ranges.Count);
            Assert.AreEqual(range, ranges[0]);
        }
        private FeedTokenEPKRange(
            string containerRid,
            CompositeContinuationToken compositeContinuationTokenByPartitionKeyRangeId)
            : this(containerRid)
        {
            if (compositeContinuationTokenByPartitionKeyRangeId == null)
            {
                throw new ArgumentNullException(nameof(compositeContinuationTokenByPartitionKeyRangeId));
            }

            this.CompleteRange = compositeContinuationTokenByPartitionKeyRangeId.Range;
            this.CompositeContinuationTokens.Enqueue(compositeContinuationTokenByPartitionKeyRangeId);

            this.currentToken = this.CompositeContinuationTokens.Peek();
        }
        public FeedTokenEPKRange(
            string containerRid,
            Documents.PartitionKeyRange keyRange)
            : this(containerRid)
        {
            if (keyRange == null)
            {
                throw new ArgumentNullException(nameof(keyRange));
            }

            this.CompleteRange = new Documents.Routing.Range <string>(keyRange.MinInclusive, keyRange.MaxExclusive, true, false);
            this.CompositeContinuationTokens.Enqueue(FeedTokenEPKRange.CreateCompositeContinuationTokenForRange(keyRange.MinInclusive, keyRange.MaxExclusive, null));

            this.currentToken = this.CompositeContinuationTokens.Peek();
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            try
            {
                Documents.Routing.Range <string> range = (Documents.Routing.Range <string>)value;

                writer.WriteStartObject();
                writer.WritePropertyName(MinProperty);
                serializer.Serialize(writer, range.Min);
                writer.WritePropertyName(MaxProperty);
                serializer.Serialize(writer, range.Max);
                writer.WriteEndObject();
            }
            catch (Exception ex)
            {
                throw new JsonSerializationException(string.Empty, ex);
            }
        }
Exemple #19
0
        public static FeedRangeEPK ReadJObject(
            JObject jObject,
            JsonSerializer serializer)
        {
            if (!jObject.TryGetValue(FeedRangeEPKConverter.RangePropertyName, out JToken rangeJToken))
            {
                throw new JsonReaderException();
            }

            try
            {
                Documents.Routing.Range <string> completeRange = (Documents.Routing.Range <string>)rangeJsonConverter.ReadJson(rangeJToken.CreateReader(), typeof(Documents.Routing.Range <string>), null, serializer);
                return(new FeedRangeEPK(completeRange));
            }
            catch (JsonSerializationException)
            {
                throw new JsonReaderException();
            }
        }
        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);
        public void FeedRangeCompositeContinuation_RequestVisitor_IfEPKAlreadyExists()
        {
            const string containerRid = "containerRid";
            const string continuation = "continuation";
            string       epkString    = Guid.NewGuid().ToString();

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("A", "B", true, false);
            FeedRangeCompositeContinuation   token = new FeedRangeCompositeContinuation(containerRid, Mock.Of <FeedRangeInternal>(), new List <Documents.Routing.Range <string> >()
            {
                range
            }, continuation);
            RequestMessage   requestMessage   = new RequestMessage();
            FeedRangeVisitor feedRangeVisitor = new FeedRangeVisitor(requestMessage);

            requestMessage.Properties[HandlerConstants.StartEpkString] = epkString;
            requestMessage.Properties[HandlerConstants.EndEpkString]   = epkString;
            token.Accept(feedRangeVisitor, ChangeFeedRequestOptions.FillContinuationToken);
            Assert.AreEqual(epkString, requestMessage.Properties[HandlerConstants.StartEpkString]);
            Assert.AreEqual(epkString, requestMessage.Properties[HandlerConstants.EndEpkString]);
        }
        private async Task <IReadOnlyList <Documents.PartitionKeyRange> > TryGetOverlappingRangesAsync(
            Documents.Routing.Range <string> targetRange,
            bool forceRefresh = false)
        {
            Debug.Assert(targetRange != null);

            IReadOnlyList <Documents.PartitionKeyRange> keyRanges = await this.pkRangeCacheDelegate(
                this.containerRid,
                new Documents.Routing.Range <string>(
                    targetRange.Min,
                    targetRange.Max,
                    isMaxInclusive: true,
                    isMinInclusive: false),
                forceRefresh);

            if (keyRanges.Count == 0)
            {
                throw new ArgumentOutOfRangeException("RequestContinuation", $"Token contains invalid range {targetRange.Min}-{targetRange.Max}");
            }

            return(keyRanges);
        }
        public void FeedRangeCompositeContinuation_RequestVisitor()
        {
            const string containerRid = "containerRid";
            const string continuation = "continuation";

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>("A", "B", true, false);
            FeedRangeCompositeContinuation   token = new FeedRangeCompositeContinuation(containerRid, Mock.Of <FeedRangeInternal>(), new List <Documents.Routing.Range <string> >()
            {
                range
            }, continuation);
            RequestMessage requestMessage = new RequestMessage();

            requestMessage.OperationType = Documents.OperationType.ReadFeed;
            requestMessage.ResourceType  = Documents.ResourceType.Document;
            FeedRangeVisitor feedRangeVisitor = new FeedRangeVisitor(requestMessage);

            token.Accept(feedRangeVisitor, ChangeFeedRequestOptions.FillContinuationToken);
            Assert.AreEqual(range.Min, requestMessage.Properties[HandlerConstants.StartEpkString]);
            Assert.AreEqual(range.Max, requestMessage.Properties[HandlerConstants.EndEpkString]);
            Assert.AreEqual(continuation, requestMessage.Headers.IfNoneMatch);
            Assert.IsTrue(requestMessage.IsPartitionKeyRangeHandlerRequired);
        }
        public FeedTokenEPKRange(
            string containerRid,
            IReadOnlyList <Documents.PartitionKeyRange> keyRanges)
            : this(containerRid)
        {
            if (keyRanges == null)
            {
                throw new ArgumentNullException(nameof(keyRanges));
            }

            if (keyRanges.Count == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(keyRanges));
            }

            this.CompleteRange = new Documents.Routing.Range <string>(keyRanges[0].MinInclusive, keyRanges[keyRanges.Count - 1].MaxExclusive, true, false);
            foreach (Documents.PartitionKeyRange keyRange in keyRanges)
            {
                this.CompositeContinuationTokens.Enqueue(FeedTokenEPKRange.CreateCompositeContinuationTokenForRange(keyRange.MinInclusive, keyRange.MaxExclusive, null));
            }

            this.currentToken = this.CompositeContinuationTokens.Peek();
        }
Exemple #25
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);

            Routing.IRoutingMapProvider routingProvider = Mock.Of <Routing.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());
        }
Exemple #26
0
 /// <summary>
 /// Returns list of effective partition key ranges for a collection.
 /// </summary>
 /// <param name="collectionResourceId">Collection for which to retrieve routing map.</param>
 /// <param name="range">This method will return all ranges which overlap this range.</param>
 /// <param name="forceRefresh">Whether forcefully refreshing the routing map is necessary</param>
 /// <returns>List of effective partition key ranges for a collection or null if collection doesn't exist.</returns>
 public abstract Task <IReadOnlyList <Documents.PartitionKeyRange> > TryGetOverlappingRangesAsync(
     string collectionResourceId,
     Documents.Routing.Range <string> range,
     bool forceRefresh = false);
Exemple #27
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);
        }
        /// <summary>
        /// <para>
        /// If a query encounters split up resuming using continuation, we need to regenerate the continuation tokens.
        /// Specifically, since after split we will have new set of ranges, we need to remove continuation token for the
        /// parent partition and introduce continuation token for the child partitions.
        /// </para>
        /// <para>
        /// This function does that. Also in that process, we also check validity of the input continuation tokens. For example,
        /// even after split the boundary ranges of the child partitions should match with the parent partitions. If the Min and Max
        /// range of a target partition in the continuation token was Min1 and Max1. Then the Min and Max range info for the two
        /// corresponding child partitions C1Min, C1Max, C2Min, and C2Max should follow the constrain below:
        ///  PMax = C2Max > C2Min > C1Max > C1Min = PMin.
        /// </para>
        /// </summary>
        /// <param name="partitionKeyRanges">The partition key ranges to extract continuation tokens for.</param>
        /// <param name="suppliedContinuationTokens">The continuation token that the user supplied.</param>
        /// <param name="targetRangeToContinuationTokenMap">The output dictionary of partition key range to continuation token.</param>
        /// <typeparam name="TContinuationToken">The type of continuation token to generate.</typeparam>
        /// <Remarks>
        /// The code assumes that merge doesn't happen and
        /// </Remarks>
        /// <returns>The index of the partition whose MinInclusive is equal to the suppliedContinuationTokens</returns>
        protected int FindTargetRangeAndExtractContinuationTokens <TContinuationToken>(
            List <PartitionKeyRange> partitionKeyRanges,
            IEnumerable <Tuple <TContinuationToken, Documents.Routing.Range <string> > > suppliedContinuationTokens,
            out Dictionary <string, TContinuationToken> targetRangeToContinuationTokenMap)
        {
            if (partitionKeyRanges == null)
            {
                throw new ArgumentNullException(nameof(partitionKeyRanges));
            }

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

            foreach (PartitionKeyRange partitionKeyRange in partitionKeyRanges)
            {
                if (partitionKeyRange == null)
                {
                    throw new ArgumentException(nameof(partitionKeyRanges));
                }
            }

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

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

            if (suppliedContinuationTokens.Count() > partitionKeyRanges.Count)
            {
                throw new ArgumentException($"{nameof(suppliedContinuationTokens)} can not have more elements than {nameof(partitionKeyRanges)}.");
            }

            targetRangeToContinuationTokenMap = new Dictionary <string, TContinuationToken>();

            // Find the minimum index.
            Tuple <TContinuationToken, Documents.Routing.Range <string> > firstContinuationTokenAndRange = suppliedContinuationTokens
                                                                                                           .OrderBy((tuple) => tuple.Item2.Min)
                                                                                                           .First();
            TContinuationToken firstContinuationToken = firstContinuationTokenAndRange.Item1;
            PartitionKeyRange  firstContinuationRange = new PartitionKeyRange
            {
                MinInclusive = firstContinuationTokenAndRange.Item2.Min,
                MaxExclusive = firstContinuationTokenAndRange.Item2.Max
            };

            int minIndex = partitionKeyRanges.BinarySearch(
                firstContinuationRange,
                Comparer <PartitionKeyRange> .Create((range1, range2) => string.CompareOrdinal(range1.MinInclusive, range2.MinInclusive)));

            if (minIndex < 0)
            {
                throw new ArgumentException($"{RMResources.InvalidContinuationToken} - Could not find continuation token: {firstContinuationToken}");
            }

            foreach (Tuple <TContinuationToken, Documents.Routing.Range <string> > suppledContinuationToken in suppliedContinuationTokens)
            {
                // find what ranges make up the supplied continuation token
                TContinuationToken continuationToken   = suppledContinuationToken.Item1;
                Documents.Routing.Range <string> range = suppledContinuationToken.Item2;

                IEnumerable <PartitionKeyRange> replacementRanges = partitionKeyRanges
                                                                    .Where((partitionKeyRange) =>
                                                                           string.CompareOrdinal(range.Min, partitionKeyRange.MinInclusive) <= 0 &&
                                                                           string.CompareOrdinal(range.Max, partitionKeyRange.MaxExclusive) >= 0)
                                                                    .OrderBy((partitionKeyRange) => partitionKeyRange.MinInclusive);

                // Could not find the child ranges
                if (replacementRanges.Count() == 0)
                {
                    throw this.queryClient.CreateBadRequestException(
                              $"{RMResources.InvalidContinuationToken} - Could not find continuation token: {continuationToken}");
                }

                // PMax = C2Max > C2Min > C1Max > C1Min = PMin.
                string parentMax = range.Max;
                string child2Max = replacementRanges.Last().MaxExclusive;
                string child2Min = replacementRanges.Last().MinInclusive;
                string child1Max = replacementRanges.First().MaxExclusive;
                string child1Min = replacementRanges.First().MinInclusive;
                string parentMin = range.Min;

                if (!(parentMax == child2Max &&
                      string.CompareOrdinal(child2Max, child2Min) >= 0 &&
                      (replacementRanges.Count() == 1 ? true : string.CompareOrdinal(child2Min, child1Max) >= 0) &&
                      string.CompareOrdinal(child1Max, child1Min) >= 0 &&
                      child1Min == parentMin))
                {
                    throw this.queryClient.CreateBadRequestException(
                              $"{RMResources.InvalidContinuationToken} - PMax = C2Max > C2Min > C1Max > C1Min = PMin: {continuationToken}");
                }

                foreach (PartitionKeyRange partitionKeyRange in replacementRanges)
                {
                    targetRangeToContinuationTokenMap.Add(partitionKeyRange.Id, continuationToken);
                }
            }

            return(minIndex);
        }
Exemple #29
0
            internal override IReadOnlyList <Documents.PartitionKeyRange> ResolveOverlapingPartitionKeyRanges(string collectionRid, Documents.Routing.Range <string> range, bool forceRefresh)
            {
                if (range.Min == Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey &&
                    range.Max == Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey)
                {
                    return(this.availablePartitionKeyRanges);
                }

                if (range.Min == this.availablePartitionKeyRanges[0].MinInclusive)
                {
                    return(new List <Documents.PartitionKeyRange>()
                    {
                        this.availablePartitionKeyRanges[0]
                    });
                }

                if (range.Min == this.availablePartitionKeyRanges[1].MinInclusive)
                {
                    return(new List <Documents.PartitionKeyRange>()
                    {
                        this.availablePartitionKeyRanges[1]
                    });
                }

                return(new List <Documents.PartitionKeyRange>()
                {
                    this.availablePartitionKeyRanges[2]
                });
            }
Exemple #30
0
 internal virtual IReadOnlyList <PartitionKeyRange> ResolveOverlapingPartitionKeyRanges(string collectionRid, Documents.Routing.Range <string> range, bool forceRefresh)
 {
     return((IReadOnlyList <PartitionKeyRange>) new List <Documents.PartitionKeyRange>()
     {
         new Documents.PartitionKeyRange()
         {
             MinInclusive = "", MaxExclusive = "FF", Id = "0"
         }
     });
 }