From 21e25e7ec59ab43c0bf6a37aadcb3e218e51ba6c Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 4 Nov 2020 00:58:15 +0000 Subject: [PATCH 01/17] Initial draft of FeedRange artifacts --- .../feedranges/FeedRangeAsyncVisitor.java | 14 ++ .../FeedRangeAsyncVisitorWithArg.java | 14 ++ .../FeedRangeCompositeContinuation.java | 53 ++++++++ .../feedranges/FeedRangeContinuation.java | 59 +++++++++ ...ocumentServiceRequestPopulatorVisitor.java | 12 ++ .../FeedRangeContinuationVisitor.java | 8 ++ .../feedranges/FeedRangeEpk.java | 114 ++++++++++++++++ .../feedranges/FeedRangeInternal.java | 67 ++++++++++ .../feedranges/FeedRangePartitionKey.java | 124 ++++++++++++++++++ .../FeedRangePartitionKeyRange.java | 114 ++++++++++++++++ .../FeedRangePartitionKeyRangeExtractor.java | 29 ++++ ...ocumentServiceRequestPopulatorVisitor.java | 26 ++++ .../feedranges/FeedRangeTransformer.java | 12 ++ .../feedranges/FeedRangeVisitor.java | 12 ++ .../feedranges/GenericFeedRangeVisitor.java | 12 ++ .../routing/PartitionKeyInternalHelper.java | 6 + .../com/azure/cosmos/models/FeedRange.java | 40 ++++++ .../main/java/com/azure/cosmos/util/Beta.java | 2 + 18 files changed, 718 insertions(+) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java new file mode 100644 index 0000000000000..ce9431448966b --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import reactor.core.publisher.Mono; + +abstract class FeedRangeAsyncVisitor { + public abstract Mono visitAsync(FeedRangePartitionKey feedRange); + + public abstract Mono visitAsync(FeedRangePartitionKeyRange feedRange); + + public abstract Mono visitAsync(FeedRangeEpk feedRange); +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java new file mode 100644 index 0000000000000..dc765746fd601 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import reactor.core.publisher.Mono; + +abstract class FeedRangeAsyncVisitorWithArg { + public abstract Mono visitAsync(FeedRangePartitionKey feedRange, TArg argument); + + public abstract Mono visitAsync(FeedRangePartitionKeyRange feedRange, TArg argument); + + public abstract Mono visitAsync(FeedRangeEpk feedRange, TArg argument); +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java new file mode 100644 index 0000000000000..93e21a2241f39 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.CosmosAsyncContainer; +import com.azure.cosmos.implementation.IRetryPolicy; +import com.azure.cosmos.implementation.RxDocumentServiceResponse; +import reactor.core.publisher.Mono; + +final class FeedRangeCompositeContinuation extends FeedRangeContinuation { + @Override + public String getContinuation() { + // TODO fabianm - Implement + return null; + } + + @Override + public void replaceContinuation(String continuationToken) { + // TODO fabianm - Implement + } + + @Override + public boolean isDone() { + // TODO fabianm - Implement + return false; + } + + @Override + public void validateContainer(String containerRid) { + // TODO fabianm - Implement + } + + @Override + public IRetryPolicy.ShouldRetryResult handleChangeFeedNotModified(RxDocumentServiceResponse responseMessage) { + // TODO fabianm - Implement + return null; + } + + @Override + public Mono handleSplitAsync( + CosmosAsyncContainer containerCore, + RxDocumentServiceResponse responseMessage) { + + // TODO fabianm - Implement + return null; + } + + @Override + public void accept(FeedRangeContinuationVisitor visitor) { + // TODO fabianm - Implement + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java new file mode 100644 index 0000000000000..f1bc55c52d90e --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.CosmosAsyncContainer; +import com.azure.cosmos.implementation.IRetryPolicy; +import com.azure.cosmos.implementation.RxDocumentServiceResponse; +import com.azure.cosmos.models.FeedRange; +import reactor.core.publisher.Mono; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +abstract class FeedRangeContinuation { + private final FeedRangeInternal feedRange; + private final String containerRid; + + // for mocking + protected FeedRangeContinuation() { + this.feedRange = null; + this.containerRid = null; + } + + public FeedRangeContinuation(String containerRid, FeedRangeInternal feedRange) { + checkNotNull(feedRange, "expected non-null feedRange"); + this.feedRange = feedRange; + this.containerRid = containerRid; + } + + public String getContainerRid() { + return this.containerRid; + } + + public FeedRangeInternal getFeedRange() { + return this.feedRange; + } + + public abstract String getContinuation(); + + public abstract void replaceContinuation(String continuationToken); + + public abstract boolean isDone(); + + public abstract void validateContainer(String containerRid); + + public static FeedRangeContinuation tryParse(String toStringValue) + { + return FeedRangeCompositeContinuation.tryParse(toStringValue); + } + + public abstract IRetryPolicy.ShouldRetryResult handleChangeFeedNotModified( + RxDocumentServiceResponse responseMessage); + + public abstract Mono handleSplitAsync( + CosmosAsyncContainer containerCore, + RxDocumentServiceResponse responseMessage); + + public abstract void accept(FeedRangeContinuationVisitor visitor); +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java new file mode 100644 index 0000000000000..9b7116c847134 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +final class FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor extends FeedRangeContinuationVisitor { + + @Override + public void visit(FeedRangeCompositeContinuation feedRangeCompositeContinuation) { + // TODO fabianm - Implement + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java new file mode 100644 index 0000000000000..669e13b6f2019 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +abstract class FeedRangeContinuationVisitor { + public abstract void visit(FeedRangeCompositeContinuation feedRangeCompositeContinuation); +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java new file mode 100644 index 0000000000000..6f6b3045a7519 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.IRoutingMapProvider; +import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.Utils; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.routing.PartitionKeyInternalHelper; +import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.PartitionKeyDefinition; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +final class FeedRangeEpk extends FeedRangeInternal { + private static final FeedRangeEpk fullRangeEPK = + new FeedRangeEpk(PartitionKeyInternalHelper.FullRange); + + private final Range range; + private final UnmodifiableList> rangeList; + + public FeedRangeEpk(final Range range) { + if (range == null) { + throw new NullPointerException("range"); + } + + this.range = range; + final ArrayList> temp = new ArrayList>(); + temp.add(range); + + this.rangeList = (UnmodifiableList>)UnmodifiableList.unmodifiableList(temp); + } + + public Range getRange() { + return this.range; + } + + public static FeedRangeEpk ForFullRange() { + return fullRangeEPK; + } + + @Override + public void accept(final FeedRangeVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this); + } + + @Override + public Mono acceptAsync(final FeedRangeAsyncVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + return visitor.visitAsync(this); + } + + @Override + public Mono>> getEffectiveRangesAsync( + final IRoutingMapProvider routingMapProvider, + final String containerRid, + final PartitionKeyDefinition partitionKeyDefinition) { + + return Mono.just(this.rangeList); + } + + @Override + public Mono> getPartitionKeyRangesAsync( + final IRoutingMapProvider routingMapProvider, + final String containerRid, + final PartitionKeyDefinition partitionKeyDefinition) { + + return routingMapProvider.tryGetOverlappingRangesAsync( + null, + containerRid, + this.range, + false, + null) + .flatMap(pkRangeHolder -> { + final ArrayList rangeList = new ArrayList(); + + if (pkRangeHolder != null) { + final List pkRanges = pkRangeHolder.v; + for (final PartitionKeyRange pkRange : pkRanges) { + rangeList.add(pkRange.getId()); + } + } + + return Mono.just((UnmodifiableList)UnmodifiableList.unmodifiableList(rangeList)); + }); + } + + @Override + public String toJsonString() { + try { + return Utils.getSimpleObjectMapper().writeValueAsString(this); + } catch (final IOException e) { + throw new IllegalArgumentException( + "Unable serialize the feed range token for an extended partition key into a JSON string", + e); + } + } + + @Override + public String toString() { + return this.range.toString(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java new file mode 100644 index 0000000000000..eedde638d63b1 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.IRoutingMapProvider; +import com.azure.cosmos.implementation.JsonSerializable; +import com.azure.cosmos.implementation.Utils; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.FeedRange; +import com.azure.cosmos.models.PartitionKeyDefinition; +import com.fasterxml.jackson.databind.ObjectMapper; +import reactor.core.publisher.Mono; + +import java.io.IOException; + +abstract class FeedRangeInternal extends JsonSerializable implements FeedRange { + public abstract void accept(FeedRangeVisitor visitor); + + public abstract Mono acceptAsync(FeedRangeAsyncVisitor visitor); + + public static FeedRangeInternal convert(final FeedRange feedRange) { + if (feedRange == null) { + throw new NullPointerException("feedRange"); + } + + if (feedRange instanceof FeedRangeInternal) { + return (FeedRangeInternal)feedRange; + } + + try { + return tryParse(feedRange.toJsonString()); + } catch (final IOException ioError) { + throw new IllegalArgumentException( + "Invalid/unknown FeedRange instance.", ioError); + } + } + + public abstract Mono>> getEffectiveRangesAsync( + IRoutingMapProvider routingMapProvider, + String containerRid, + PartitionKeyDefinition partitionKeyDefinition); + + public abstract Mono> getPartitionKeyRangesAsync( + IRoutingMapProvider routingMapProvider, + String containerRid, + PartitionKeyDefinition partitionKeyDefinition); + + @Override + public String toJsonString() { + return this.toJson(); + } + + @Override + public abstract String toString(); + + public static FeedRangeInternal tryParse(final String jsonString) throws IOException { + if (jsonString == null) { + throw new NullPointerException("jsonString"); + } + + final ObjectMapper mapper = Utils.getSimpleObjectMapper(); + final FeedRangeInternal feedRange = mapper.readValue(jsonString, FeedRangeInternal.class); + return feedRange; + } +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java new file mode 100644 index 0000000000000..a4fae18c6418f --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.IRoutingMapProvider; +import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.routing.PartitionKeyInternal; +import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.PartitionKeyDefinition; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.Collections; + +final class FeedRangePartitionKey extends FeedRangeInternal { + private final PartitionKeyInternal partitionKey; + + public FeedRangePartitionKey(PartitionKeyInternal partitionKey) { + if (partitionKey == null) { + throw new NullPointerException("partitionKey"); + } + + this.partitionKey = partitionKey; + } + + public PartitionKeyInternal getPartitionKeyInternal() { + return this.partitionKey; + } + + @Override + public void accept(FeedRangeVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this); + } + + @Override + public Mono acceptAsync(FeedRangeAsyncVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + return visitor.visitAsync(this); + } + + @Override + public Mono>> getEffectiveRangesAsync( + IRoutingMapProvider routingMapProvider, + String containerRid, + PartitionKeyDefinition partitionKeyDefinition) { + + String effectivePartitionKey = this.partitionKey.getEffectivePartitionKeyString( + this.partitionKey, + partitionKeyDefinition); + Range range = Range.getPointRange(effectivePartitionKey); + ArrayList> rangeList = new ArrayList>(); + rangeList.add(range); + + return Mono.just((UnmodifiableList>)UnmodifiableList.unmodifiableList(rangeList)); + } + + @Override + public Mono> getPartitionKeyRangesAsync( + IRoutingMapProvider routingMapProvider, + String containerRid, + PartitionKeyDefinition partitionKeyDefinition) { + + String effectivePartitionKey = this.partitionKey.getEffectivePartitionKeyString( + this.partitionKey, + partitionKeyDefinition); + return routingMapProvider + .tryGetOverlappingRangesAsync( + null, + containerRid, + Range.getPointRange(effectivePartitionKey), + false, + null) + .flatMap(pkRangeHolder -> { + ArrayList rangeList = new ArrayList(); + + if (pkRangeHolder != null) { + String rangeId = pkRangeHolder.v.get(0).getId(); + rangeList.add(rangeId); + } + + return Mono.just((UnmodifiableList)UnmodifiableList.unmodifiableList(rangeList)); + }); + } + + @Override + public String toJsonString() { + return this.partitionKey.toJson(); + } + + @Override + public String toString() { + return this.partitionKey.toJson(); + } + + private static Mono tryGetRangeByEffectivePartitionKey( + IRoutingMapProvider routingMapProvider, + String containerRid, + String effectivePartitionKey) { + + return routingMapProvider + .tryGetOverlappingRangesAsync( + null, + containerRid, + Range.getPointRange(effectivePartitionKey), + false, + null) + .flatMap((pkRangeHolder) -> { + if (pkRangeHolder == null) { + return Mono.empty(); + } + + return Mono.just(pkRangeHolder.v.get(0)); + }); + } +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java new file mode 100644 index 0000000000000..f2978cbf9b036 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.IRoutingMapProvider; +import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.Utils.ValueHolder; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; +import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.PartitionKeyDefinition; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.Collections; + +final class FeedRangePartitionKeyRange extends FeedRangeInternal { + private final String partitionKeyRangeId; + private final PartitionKeyRangeIdentity partitionKeyRangeIdentity; + + public FeedRangePartitionKeyRange(final String partitionKeyRangeId) { + if (partitionKeyRangeId == null) { + throw new NullPointerException("partitionKeyRangeId"); + } + + this.partitionKeyRangeId = partitionKeyRangeId; + this.partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(partitionKeyRangeId); + } + + public String getPartitionKeyRangeId() { + return this.partitionKeyRangeId; + } + + public PartitionKeyRangeIdentity getPartitionKeyRangeIdentity() { + return this.partitionKeyRangeIdentity; + } + + @Override + public void accept(final FeedRangeVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this); + } + + @Override + public Mono acceptAsync(final FeedRangeAsyncVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + return visitor.visitAsync(this); + } + + @Override + public Mono>> getEffectiveRangesAsync( + final IRoutingMapProvider routingMapProvider, + final String containerRid, + final PartitionKeyDefinition partitionKeyDefinition) { + + final Mono> getPkRangeTask = routingMapProvider + .tryGetPartitionKeyRangeByIdAsync( + null, + containerRid, + partitionKeyRangeId, + false, + null) + .flatMap((pkRangeHolder) -> { + if (pkRangeHolder == null) { + return routingMapProvider.tryGetPartitionKeyRangeByIdAsync( + null, + containerRid, + partitionKeyRangeId, + true, + null); + } else { + return Mono.just(pkRangeHolder); + } + }); + + return getPkRangeTask.flatMap((pkRangeHolder) -> { + final ArrayList> temp = new ArrayList>(); + if (pkRangeHolder != null) { + temp.add(pkRangeHolder.v.toRange()); + } + + return Mono.just((UnmodifiableList>)UnmodifiableList.unmodifiableList(temp)); + }); + } + + @Override + public Mono> getPartitionKeyRangesAsync( + final IRoutingMapProvider routingMapProvider, + final String containerRid, + final PartitionKeyDefinition partitionKeyDefinition) { + + final ArrayList temp = new ArrayList(); + temp.add(this.partitionKeyRangeId); + + return Mono.just((UnmodifiableList)UnmodifiableList.unmodifiableList(temp)); + } + + @Override + public String toJsonString() { + return this.partitionKeyRangeId; + } + + @Override + public String toString() { + return this.partitionKeyRangeId; + } +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java new file mode 100644 index 0000000000000..1f0c92d539572 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.routing.Range; +import reactor.core.publisher.Mono; + +import java.util.List; + +final class FeedRangePartitionKeyRangeExtractor extends FeedRangeAsyncVisitor>> { + @Override + public Mono>> visitAsync(FeedRangePartitionKey feedRange) { + // TODO fabianm - Implement + return null; + } + + @Override + public Mono>> visitAsync(FeedRangePartitionKeyRange feedRange) { + // TODO fabianm - Implement + return null; + } + + @Override + public Mono>> visitAsync(FeedRangeEpk feedRange) { + // TODO fabianm - Implement + return null; + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java new file mode 100644 index 0000000000000..ad7129114b64c --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.RxDocumentServiceRequest; + +final class FeedRangeRxDocumentServiceRequestPopulatorVisitor + extends GenericFeedRangeVisitor { + + @Override + public void visit(FeedRangeEpk feedRange, + RxDocumentServiceRequest rxDocumentServiceRequest) { + // TODO fabianm - Implement + } + + @Override + public void visit(FeedRangePartitionKeyRange feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { + // TODO fabianm - Implement + } + + @Override + public void visit(FeedRangePartitionKey feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { + // TODO fabianm - Implement + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java new file mode 100644 index 0000000000000..ea045a8cac82f --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +abstract class FeedRangeTransformer { + public abstract TResult visit(FeedRangePartitionKey feedRange); + + public abstract TResult visit(FeedRangePartitionKeyRange feedRange); + + public abstract TResult visit(FeedRangeEpk feedRange); +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java new file mode 100644 index 0000000000000..d41e406bde240 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +abstract class FeedRangeVisitor { + public abstract void visit(FeedRangeEpk feedRange); + + public abstract void visit(FeedRangePartitionKeyRange feedRange); + + public abstract void visit(FeedRangePartitionKey feedRange); +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java new file mode 100644 index 0000000000000..f523581d432ad --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +abstract class GenericFeedRangeVisitor { + public abstract void visit(FeedRangeEpk feedRange, TInput input); + + public abstract void visit(FeedRangePartitionKeyRange feedRange, TInput input); + + public abstract void visit(FeedRangePartitionKey feedRange, TInput input); +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/PartitionKeyInternalHelper.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/PartitionKeyInternalHelper.java index 63bd1389a0217..de4750ece8aaf 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/PartitionKeyInternalHelper.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/routing/PartitionKeyInternalHelper.java @@ -19,6 +19,12 @@ public class PartitionKeyInternalHelper { public static final String MinimumInclusiveEffectivePartitionKey = toHexEncodedBinaryString(PartitionKeyInternal.EmptyPartitionKey.components); public static final String MaximumExclusiveEffectivePartitionKey = toHexEncodedBinaryString(PartitionKeyInternal.InfinityPartitionKey.components); + public static final Range FullRange = new Range( + PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, + PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey, + true, + false); + static final int MaxPartitionKeyBinarySize = (1 /*type marker */ + 9 /* hash value*/ + diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java new file mode 100644 index 0000000000000..3f369f6212576 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.models; + +import com.azure.cosmos.implementation.feedranges.FeedRangeInternal; +import com.azure.cosmos.util.Beta; + +import java.io.IOException; + +@Beta(Beta.SinceVersion.V4_9_0) +public interface FeedRange { + /** + * Creates a range from a previously obtained string representation. + * + * @param json A string representation of a feed range + * @return A feed range + */ + public static FeedRange fromJsonString(String json) { + FeedRange parsedRange = null; + + try { + parsedRange = FeedRangeInternal.tryParse(json); + } catch (IOException e) { + throw new IllegalArgumentException( + String.format("Unable to parse JSON %s", json), e); + } + + if (parsedRange == null) { + throw new IllegalArgumentException( + String.format( + "The provided string '%s' does not represent any known format.", + json)); + } + + return parsedRange; + } + + public String toJsonString(); +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java index c981a2fe3f113..ac92720730665 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java @@ -48,5 +48,7 @@ public enum SinceVersion { V4_7_0, /** v4.8.0 */ V4_8_0, + /** v4.9.0 */ + V4_9_0, } } From 40ef415a3f00188fc0a204cd0dc214cde0bbf46d Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 5 Nov 2020 00:29:56 +0000 Subject: [PATCH 02/17] Iterating on FeedRange Apis --- .../implementation/ClientRetryPolicy.java | 2 - .../cosmos/implementation/HttpConstants.java | 4 + .../cosmos/implementation/IRetryPolicy.java | 58 --- .../cosmos/implementation/RetryUtils.java | 8 +- .../RxDocumentServiceRequest.java | 9 + .../implementation/ShouldRetryResult.java | 61 +++ .../GoneAndRetryWithRetryPolicy.java | 1 + .../EpkRequestPropertyConstants.java | 9 + .../FeedRangeCompositeContinuation.java | 358 +++++++++++++++++- .../feedranges/FeedRangeContinuation.java | 12 +- ...ocumentServiceRequestPopulatorVisitor.java | 37 +- .../feedranges/FeedRangeInternal.java | 2 +- .../FeedRangePartitionKeyRangeExtractor.java | 88 ++++- ...ocumentServiceRequestPopulatorVisitor.java | 43 ++- .../query/CompositeContinuationToken.java | 4 +- .../cosmos/RetryContextOnDiagnosticTest.java | 3 +- .../implementation/ClientRetryPolicyTest.java | 30 +- ...eCollectionAwareClientRetryPolicyTest.java | 11 +- .../cosmos/implementation/RetryUtilsTest.java | 1 - .../implementation/ShouldRetryValidator.java | 18 +- .../GoneAndRetryWithRetryPolicyTest.java | 34 +- 21 files changed, 642 insertions(+), 151 deletions(-) create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java create mode 100644 sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/EpkRequestPropertyConstants.java diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientRetryPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientRetryPolicy.java index ec4c55cc48edc..9a7a08ed06752 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientRetryPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ClientRetryPolicy.java @@ -4,11 +4,9 @@ import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.directconnectivity.WebExceptionUtility; -import com.azure.cosmos.BridgeInternal; import com.azure.cosmos.CosmosException; import com.azure.cosmos.CosmosDiagnostics; import com.azure.cosmos.ThrottlingRetryOptions; -import io.netty.handler.timeout.ReadTimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HttpConstants.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HttpConstants.java index e9ae3b407e2c6..ff0281744bc4d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HttpConstants.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/HttpConstants.java @@ -272,6 +272,9 @@ public static class Versions { public static class StatusCodes { public static final int OK = 200; public static final int NOT_MODIFIED = 304; + // Success + public static final int MINIMUM_SUCCESS_STATUSCODE = 200; + public static final int MAXIMUM_SUCCESS_STATUSCODE = 299; // Client error public static final int MINIMUM_STATUSCODE_AS_ERROR_GATEWAY = 400; public static final int BADREQUEST = 400; @@ -323,5 +326,6 @@ public static class SubStatusCodes { public static class HeaderValues { public static final String NO_CACHE = "no-cache"; public static final String PREFER_RETURN_MINIMAL = "return=minimal"; + public static final String IF_NONE_MATCH_ALL = "*"; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/IRetryPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/IRetryPolicy.java index 741f59b6c381b..def325becc0ab 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/IRetryPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/IRetryPolicy.java @@ -43,62 +43,4 @@ public interface IRetryPolicy { void addStatusAndSubStatusCode(Integer index, int statusCode, int subStatusCode); List getStatusAndSubStatusCodes(); - - class ShouldRetryResult { - /// - /// How long to wait before next retry. 0 indicates retry immediately. - /// - public final Duration backOffTime; - public final Exception exception; - public boolean shouldRetry; - public final Quadruple policyArg; - - private ShouldRetryResult(Duration dur, Exception e, boolean shouldRetry, - Quadruple policyArg) { - this.backOffTime = dur; - this.exception = e; - this.shouldRetry = shouldRetry; - this.policyArg = policyArg; - } - - public static ShouldRetryResult retryAfter(Duration dur) { - Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); - return new ShouldRetryResult(dur, null, true, null); - } - - public static ShouldRetryResult retryAfter(Duration dur, - Quadruple policyArg) { - Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); - return new ShouldRetryResult(dur, null, true, policyArg); - } - - public static ShouldRetryResult error(Exception e) { - Utils.checkNotNullOrThrow(e, "exception", "cannot be null"); - return new ShouldRetryResult(null, e, false, null); - } - - public static ShouldRetryResult noRetry() { - return new ShouldRetryResult(null, null, false, null); - } - - public static ShouldRetryResult noRetry(Quadruple policyArg) { - return new ShouldRetryResult( - null, - null, - false, - policyArg); - } - - public void throwIfDoneTrying(Exception capturedException) throws Exception { - if (this.shouldRetry) { - return; - } - - if (this.exception == null) { - throw capturedException; - } else { - throw this.exception; - } - } - } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RetryUtils.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RetryUtils.java index 491058ba56ede..8d0df57f39a99 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RetryUtils.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RetryUtils.java @@ -28,7 +28,7 @@ static Function, Flux> toRetryWhenFunc(IRetryPolicy policy return Flux.error(t); } policy.captureStartTimeIfNotSet(); - Flux shouldRetryResultFlux = policy.shouldRetry(e).flux(); + Flux shouldRetryResultFlux = policy.shouldRetry(e).flux(); return shouldRetryResultFlux.flatMap(s -> { CosmosException clientException = Utils.as(e, CosmosException.class); if(clientException != null) { @@ -76,7 +76,7 @@ public static Function> toRetryWithAlternateFunc(Function return Mono.error(throwable); } retryPolicy.captureStartTimeIfNotSet(); - Mono shouldRetryResultFlux = retryPolicy.shouldRetry(e); + Mono shouldRetryResultFlux = retryPolicy.shouldRetry(e); return shouldRetryResultFlux.flatMap(shouldRetryResult -> { CosmosException clientException = Utils.as(e, CosmosException.class); if(clientException != null) { @@ -140,7 +140,7 @@ private static Mono recursiveFunc( Function, Mono> callbackMethod, IRetryPolicy retryPolicy, Function, Mono> inBackoffAlternateCallbackMethod, - IRetryPolicy.ShouldRetryResult shouldRetryResult, + ShouldRetryResult shouldRetryResult, Duration minBackoffForInBackoffCallback, RxDocumentServiceRequest rxDocumentServiceRequest, AddressSelector addressSelector) { @@ -153,7 +153,7 @@ private static Function> recursiveWithAlternateFunc( Function, Mono> callbackMethod, IRetryPolicy retryPolicy, Function, Mono> inBackoffAlternateCallbackMethod, - IRetryPolicy.ShouldRetryResult shouldRetryResult, + ShouldRetryResult shouldRetryResult, StopWatch stopwatch, Duration minBackoffForInBackoffCallback, RxDocumentServiceRequest rxDocumentServiceRequest, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java index 74fec255cb556..365f336412fe5 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java @@ -1010,6 +1010,15 @@ public void dispose() { this.isDisposed = true; } + /** + * Gets the request properties. + * + * @return the request properties. + */ + public Map getProperties() { + return this.properties; + } + private static Map getProperties(Object options) { if (options == null) { return null; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java new file mode 100644 index 0000000000000..0030cbe2a62e9 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java @@ -0,0 +1,61 @@ +package com.azure.cosmos.implementation; + +import java.time.Duration; + +public class ShouldRetryResult { + /// + /// How long to wait before next retry. 0 indicates retry immediately. + /// + public final Duration backOffTime; + public final Exception exception; + public boolean shouldRetry; + public final Quadruple policyArg; + + private ShouldRetryResult(Duration dur, Exception e, boolean shouldRetry, + Quadruple policyArg) { + this.backOffTime = dur; + this.exception = e; + this.shouldRetry = shouldRetry; + this.policyArg = policyArg; + } + + public static ShouldRetryResult retryAfter(Duration dur) { + Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); + return new ShouldRetryResult(dur, null, true, null); + } + + public static ShouldRetryResult retryAfter(Duration dur, + Quadruple policyArg) { + Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); + return new ShouldRetryResult(dur, null, true, policyArg); + } + + public static ShouldRetryResult error(Exception e) { + Utils.checkNotNullOrThrow(e, "exception", "cannot be null"); + return new ShouldRetryResult(null, e, false, null); + } + + public static ShouldRetryResult noRetry() { + return new ShouldRetryResult(null, null, false, null); + } + + public static ShouldRetryResult noRetry(Quadruple policyArg) { + return new ShouldRetryResult( + null, + null, + false, + policyArg); + } + + public void throwIfDoneTrying(Exception capturedException) throws Exception { + if (this.shouldRetry) { + return; + } + + if (this.exception == null) { + throw capturedException; + } else { + throw this.exception; + } + } +} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java index 8a28a8ee774fd..37fa709d6838d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java @@ -14,6 +14,7 @@ import com.azure.cosmos.implementation.RetryPolicyWithDiagnostics; import com.azure.cosmos.implementation.RetryWithException; import com.azure.cosmos.implementation.RxDocumentServiceRequest; +import com.azure.cosmos.implementation.ShouldRetryResult; import com.azure.cosmos.implementation.apachecommons.lang.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/EpkRequestPropertyConstants.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/EpkRequestPropertyConstants.java new file mode 100644 index 0000000000000..33cab77a02376 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/EpkRequestPropertyConstants.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.implementation.feedranges; + +final class EpkRequestPropertyConstants { + public final static String END_EPK_STRING = "x-ms-end-epk-string"; + public final static String START_EPK_STRING = "x-ms-start-epk-string"; +} \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java index 93e21a2241f39..c3b7ae6316578 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java @@ -3,51 +3,371 @@ package com.azure.cosmos.implementation.feedranges; -import com.azure.cosmos.CosmosAsyncContainer; -import com.azure.cosmos.implementation.IRetryPolicy; +import com.azure.cosmos.implementation.HttpConstants; +import com.azure.cosmos.implementation.Integers; +import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.RxDocumentClientImpl; import com.azure.cosmos.implementation.RxDocumentServiceResponse; +import com.azure.cosmos.implementation.ShouldRetryResult; +import com.azure.cosmos.implementation.Strings; +import com.azure.cosmos.implementation.Utils; +import com.azure.cosmos.implementation.caches.RxPartitionKeyRangeCache; +import com.azure.cosmos.implementation.query.CompositeContinuationToken; +import com.azure.cosmos.implementation.routing.Range; +import com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.publisher.Mono; +import java.io.IOException; +import java.time.Duration; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + +/** + * FeedRangeContinuation using Composite Continuation Tokens and split proof. + * It uses a breath-first approach to transverse Composite Continuation Tokens. + */ final class FeedRangeCompositeContinuation extends FeedRangeContinuation { + + private final static ShouldRetryResult RETRY = ShouldRetryResult.retryAfter(Duration.ZERO); + private final static ShouldRetryResult NO_RETRY = ShouldRetryResult.noRetry(); + + private final Queue compositeContinuationTokens; + private CompositeContinuationToken currentToken; + private String initialNoResultsRange; + + private FeedRangeCompositeContinuation(String containerRid, FeedRangeInternal feedRange) { + super(containerRid, feedRange); + + this.compositeContinuationTokens = new LinkedList(); + } + + public FeedRangeCompositeContinuation( + String containerRid, + FeedRangeInternal feedRange, + List> ranges) { + + this(containerRid, feedRange, ranges, null); + } + + public FeedRangeCompositeContinuation( + String containerRid, + FeedRangeInternal feedRange, + List> ranges, + String continuation) { + + this(containerRid, feedRange); + + checkNotNull(ranges, "'ranges' must not be null"); + + if (ranges.size() == 0) { + throw new IllegalArgumentException("'ranges' must not be empty"); + } + + for (Range range : ranges) { + this.compositeContinuationTokens.add( + FeedRangeCompositeContinuation.createCompositeContinuationTokenForRange( + range.getMin(), + range.getMax(), + continuation) + ); + } + + this.currentToken = this.getCompositeContinuationTokens().peek(); + } + + /** + * Used for deserializtion only + */ + public static FeedRangeCompositeContinuation createFromDeserializedTokens( + String containerRid, + FeedRangeInternal feedRange, + List deserializedTokens) { + + FeedRangeCompositeContinuation thisPtr = new FeedRangeCompositeContinuation(containerRid, feedRange); + + checkNotNull(deserializedTokens, "'deserializedTokens' must not be null"); + + if (deserializedTokens.size() == 0) { + throw new IllegalArgumentException("'deserializedTokens' must not be empty"); + } + + for (CompositeContinuationToken token : deserializedTokens) { + thisPtr.compositeContinuationTokens.add(token); + } + + thisPtr.currentToken = thisPtr.getCompositeContinuationTokens().peek(); + + return thisPtr; + } + + public Queue getCompositeContinuationTokens() { + return getCompositeContinuationTokens(); + } + + public CompositeContinuationToken getCurrentToken() { + return this.currentToken; + } + @Override public String getContinuation() { - // TODO fabianm - Implement + CompositeContinuationToken tokenSnapshot = this.currentToken; + if (tokenSnapshot == null) { + return null; + } + + return tokenSnapshot.getToken(); + } + + @Override + public FeedRangeInternal getFeedRange() { + if (!(this.feedRange instanceof FeedRangeEpk)) + { + return this.feedRange; + } + + if (this.currentToken != null) + { + return new FeedRangeEpk(this.currentToken.getRange()); + } + return null; } @Override - public void replaceContinuation(String continuationToken) { - // TODO fabianm - Implement + public String toString() { + try { + return Utils.getSimpleObjectMapper().writeValueAsString(this); + } catch (final IOException e) { + throw new IllegalArgumentException( + "Unable serialize the composite FeedRange continuation token into a JSON string", + e); + } + } + + @Override + public void replaceContinuation(final String continuationToken) { + final CompositeContinuationToken continuationTokenSnapshot = this.currentToken; + + if (continuationTokenSnapshot == null) { + return; + } + + continuationTokenSnapshot.setToken(continuationToken); + this.moveToNextToken(); } @Override public boolean isDone() { - // TODO fabianm - Implement - return false; + return this.compositeContinuationTokens.size() == 0; } @Override - public void validateContainer(String containerRid) { - // TODO fabianm - Implement + public void validateContainer(final String containerRid) throws IllegalArgumentException { + if (Strings.isNullOrEmpty(containerRid) || !containerRid.equals(this.getContainerRid())) { + + final String message = String.format( + "The continuation was generated for container %s but current container is %s.", + this.getContainerRid(), containerRid); + throw new IllegalArgumentException(message); + } } @Override - public IRetryPolicy.ShouldRetryResult handleChangeFeedNotModified(RxDocumentServiceResponse responseMessage) { - // TODO fabianm - Implement - return null; + public ShouldRetryResult handleChangeFeedNotModified(final RxDocumentServiceResponse response) { + if (response == null) { + throw new NullPointerException("response"); + } + + final int statusCode = response.getStatusCode(); + if (statusCode >= HttpConstants.StatusCodes.MINIMUM_SUCCESS_STATUSCODE + && statusCode <= HttpConstants.StatusCodes.MAXIMUM_SUCCESS_STATUSCODE) { + + this.initialNoResultsRange = null; + return NO_RETRY; + } + + if (statusCode == HttpConstants.StatusCodes.NOT_MODIFIED && this.compositeContinuationTokens.size() > 1) { + + final String eTag = response.getResponseHeaders().get(HttpConstants.HttpHeaders.E_TAG); + if (this.initialNoResultsRange == null) { + + this.initialNoResultsRange = this.currentToken.getRange().getMin(); + this.replaceContinuation(eTag); + return RETRY; + } + + if (!this.initialNoResultsRange.equalsIgnoreCase(this.currentToken.getRange().getMin())) { + this.replaceContinuation(eTag); + return RETRY; + } + } + + return NO_RETRY; } @Override - public Mono handleSplitAsync( - CosmosAsyncContainer containerCore, - RxDocumentServiceResponse responseMessage) { + public Mono handleSplitAsync(final RxDocumentClientImpl client, + final RxDocumentServiceResponse response) { - // TODO fabianm - Implement - return null; + if (client == null) { + throw new NullPointerException("client"); + } + + if (response == null) { + throw new NullPointerException("response"); + } + + Integer nSubStatus = 0; + final String valueSubStatus = + response.getResponseHeaders().get(HttpConstants.HttpHeaders.SUB_STATUS); + if (!Strings.isNullOrEmpty(valueSubStatus)) { + nSubStatus = Integers.tryParse(valueSubStatus); + } + + final Boolean partitionSplit = + response.getStatusCode() == HttpConstants.StatusCodes.GONE && nSubStatus != null + && (nSubStatus.intValue() == HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE + || nSubStatus.intValue() == HttpConstants.SubStatusCodes.COMPLETING_SPLIT); + + if (!partitionSplit) { + return Mono.just(NO_RETRY); + } + + final RxPartitionKeyRangeCache partitionKeyRangeCache = client.getPartitionKeyRangeCache(); + final Mono>> resolvedRangesTask = + this.tryGetOverlappingRangesAsync( + partitionKeyRangeCache, this.currentToken.getRange().getMin(), + this.currentToken.getRange().getMax(), + true); + + final Mono result = resolvedRangesTask.flatMap(resolvedRanges -> { + if (resolvedRanges.v != null && resolvedRanges.v.size() > 0) { + this.createChildRanges(resolvedRanges.v); + } + + return Mono.just(RETRY); + }); + + return result; } @Override - public void accept(FeedRangeContinuationVisitor visitor) { - // TODO fabianm - Implement + public void accept(final FeedRangeContinuationVisitor visitor) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this); + } + + public static FeedRangeContinuation parse(final String jsonString) throws IOException { + if (jsonString == null) { + throw new NullPointerException("jsonString"); + } + + final ObjectMapper mapper = Utils.getSimpleObjectMapper(); + + return mapper.readValue(jsonString, FeedRangeCompositeContinuation.class); + } + + private static CompositeContinuationToken createCompositeContinuationTokenForRange( + String minInclusive, + String maxExclusive, + String token) + { + return new CompositeContinuationToken( + token, + new Range(minInclusive, maxExclusive, true, false)); + } + + private static CompositeContinuationToken tryParseAsCompositeContinuationToken( + final String providedContinuation) { + + try { + final ObjectMapper mapper = Utils.getSimpleObjectMapper(); + + if (providedContinuation.trim().startsWith("[")) { + final List compositeContinuationTokens = Arrays + .asList(mapper.readValue(providedContinuation, + CompositeContinuationToken[].class)); + + if (compositeContinuationTokens != null && compositeContinuationTokens.size() > 0) { + return compositeContinuationTokens.get(0); + } + + return null; + } else if (providedContinuation.trim().startsWith("{")) { + return mapper.readValue(providedContinuation, CompositeContinuationToken.class); + } + + return null; + } catch (final IOException ioError) { + return null; + } + } + + private void createChildRanges(final List keyRanges) { + final PartitionKeyRange firstRange = keyRanges.get(0); + this.currentToken + .setRange(new Range(firstRange.getMinInclusive(), + firstRange.getMaxExclusive(), true, false)); + + final CompositeContinuationToken continuationAsComposite = + tryParseAsCompositeContinuationToken( + this.currentToken.getToken()); + + if (continuationAsComposite != null) { + // Update the internal composite continuation + continuationAsComposite.setRange(this.currentToken.getRange()); + this.currentToken.setToken(continuationAsComposite.toJson()); + // Add children + final int size = keyRanges.size(); + for (int i = 1; i < size; i++) { + final PartitionKeyRange keyRange = keyRanges.get(i); + continuationAsComposite.setRange(keyRange.toRange()); + this.compositeContinuationTokens.add(createCompositeContinuationTokenForRange( + keyRange.getMinInclusive(), keyRange.getMaxExclusive(), + continuationAsComposite.toJson())); + } + } else { + // Add children + final int size = keyRanges.size(); + for (int i = 1; i < size; i++) { + final PartitionKeyRange keyRange = keyRanges.get(i); + this.compositeContinuationTokens.add(createCompositeContinuationTokenForRange( + keyRange.getMinInclusive(), keyRange.getMaxExclusive(), + this.currentToken.getToken())); + } + } + } + + private void moveToNextToken() { + final CompositeContinuationToken recentToken = this.compositeContinuationTokens.poll(); + if (recentToken.getToken() != null) { + // Normal ReadFeed can signal termination by CT null, not NotModified + // Change Feed never lands here, as it always provides a CT + // Consider current range done, if this FeedToken contains multiple ranges due + // to splits, + // all of them need to be considered done + this.compositeContinuationTokens.add(recentToken); + } + + if (this.compositeContinuationTokens.size() > 0) { + this.currentToken = this.compositeContinuationTokens.peek(); + } else { + this.currentToken = null; + } + } + + private Mono>> tryGetOverlappingRangesAsync( + final RxPartitionKeyRangeCache partitionKeyRangeCache, final String min, final String max, + final Boolean forceRefresh) { + + return partitionKeyRangeCache.tryGetOverlappingRangesAsync(null, this.getContainerRid(), + new Range(min, max, false, true), forceRefresh, null); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java index f1bc55c52d90e..43baf1e0520c3 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java @@ -4,15 +4,15 @@ package com.azure.cosmos.implementation.feedranges; import com.azure.cosmos.CosmosAsyncContainer; -import com.azure.cosmos.implementation.IRetryPolicy; +import com.azure.cosmos.implementation.RxDocumentClientImpl; import com.azure.cosmos.implementation.RxDocumentServiceResponse; -import com.azure.cosmos.models.FeedRange; +import com.azure.cosmos.implementation.ShouldRetryResult; import reactor.core.publisher.Mono; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; abstract class FeedRangeContinuation { - private final FeedRangeInternal feedRange; + protected final FeedRangeInternal feedRange; private final String containerRid; // for mocking @@ -48,11 +48,11 @@ public static FeedRangeContinuation tryParse(String toStringValue) return FeedRangeCompositeContinuation.tryParse(toStringValue); } - public abstract IRetryPolicy.ShouldRetryResult handleChangeFeedNotModified( + public abstract ShouldRetryResult handleChangeFeedNotModified( RxDocumentServiceResponse responseMessage); - public abstract Mono handleSplitAsync( - CosmosAsyncContainer containerCore, + public abstract Mono handleSplitAsync( + RxDocumentClientImpl client, RxDocumentServiceResponse responseMessage); public abstract void accept(FeedRangeContinuationVisitor visitor); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java index 9b7116c847134..a7dce884c5544 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java @@ -3,10 +3,45 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.RxDocumentServiceRequest; +import com.azure.cosmos.implementation.routing.Range; + +import java.util.Map; +import java.util.function.BiConsumer; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + final class FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor extends FeedRangeContinuationVisitor { + private final RxDocumentServiceRequest request; + private final BiConsumer fillContinuation; + + public FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor( + RxDocumentServiceRequest request, BiConsumer fillContinuation) + { + checkNotNull(request, "'request' must not be null"); + checkNotNull(fillContinuation, "'fillContinuation' must not be null"); + + this.request = request; + this.fillContinuation = fillContinuation; + } + @Override public void visit(FeedRangeCompositeContinuation feedRangeCompositeContinuation) { - // TODO fabianm - Implement + checkNotNull(feedRangeCompositeContinuation, "'feedRangeCompositeContinuation' must not be null"); + + final Map properties = this.request.getProperties(); + + // In case EPK has already been set by compute + if (properties.containsKey(EpkRequestPropertyConstants.START_EPK_STRING)) { + return; + } + + final Range range = feedRangeCompositeContinuation.getCurrentToken().getRange(); + + properties.put(EpkRequestPropertyConstants.END_EPK_STRING, range.getMax()); + properties.put(EpkRequestPropertyConstants.START_EPK_STRING, range.getMin()); + + this.fillContinuation.accept(this.request, feedRangeCompositeContinuation.getContinuation()); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java index eedde638d63b1..91771bd29d0eb 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -15,7 +15,7 @@ import java.io.IOException; -abstract class FeedRangeInternal extends JsonSerializable implements FeedRange { +public abstract class FeedRangeInternal extends JsonSerializable implements FeedRange { public abstract void accept(FeedRangeVisitor visitor); public abstract Mono acceptAsync(FeedRangeAsyncVisitor visitor); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java index 1f0c92d539572..9b80b75943409 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java @@ -3,27 +3,103 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.BridgeInternal; +import com.azure.cosmos.implementation.DocumentCollection; +import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.ResourceResponse; +import com.azure.cosmos.implementation.RxDocumentClientImpl; +import com.azure.cosmos.implementation.Utils; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.caches.RxPartitionKeyRangeCache; import com.azure.cosmos.implementation.routing.Range; import reactor.core.publisher.Mono; +import java.util.ArrayList; import java.util.List; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + final class FeedRangePartitionKeyRangeExtractor extends FeedRangeAsyncVisitor>> { + + private final RxDocumentClientImpl client; + private final String collectionLink; + + public FeedRangePartitionKeyRangeExtractor( + RxDocumentClientImpl client, + String collectionLink) { + + checkNotNull(client, "'client' must not be null"); + checkNotNull(collectionLink, "'collectionLink' must not be null"); + + this.client = client; + this.collectionLink = collectionLink; + } + @Override public Mono>> visitAsync(FeedRangePartitionKey feedRange) { - // TODO fabianm - Implement - return null; + final RxPartitionKeyRangeCache partitionKeyRangeCache = + this.client.getPartitionKeyRangeCache(); + final Mono> collectionResponseObservable = this.client + .readCollection(this.collectionLink, null); + + return collectionResponseObservable.flatMap(collectionResponse -> { + final DocumentCollection collection = collectionResponse.getResource(); + return feedRange.getEffectiveRangesAsync(partitionKeyRangeCache, + collection.getResourceId(), + collection.getPartitionKey()); + }); } @Override public Mono>> visitAsync(FeedRangePartitionKeyRange feedRange) { - // TODO fabianm - Implement - return null; + final RxPartitionKeyRangeCache partitionKeyRangeCache = + this.client.getPartitionKeyRangeCache(); + final Mono> collectionResponseObservable = this.client + .readCollection(this.collectionLink, null); + + return collectionResponseObservable.flatMap(collectionResponse -> { + final DocumentCollection collection = collectionResponse.getResource(); + return feedRange.getEffectiveRangesAsync(partitionKeyRangeCache, + collection.getResourceId(), null); + }); } @Override public Mono>> visitAsync(FeedRangeEpk feedRange) { - // TODO fabianm - Implement - return null; + final RxPartitionKeyRangeCache partitionKeyRangeCache = + this.client.getPartitionKeyRangeCache(); + final Mono> collectionResponseObservable = this.client + .readCollection(this.collectionLink, null); + + final Mono>> valueHolderMono = + collectionResponseObservable + .flatMap(collectionResponse -> { + final DocumentCollection collection = collectionResponse.getResource(); + return partitionKeyRangeCache.tryGetOverlappingRangesAsync( + BridgeInternal.getMetaDataDiagnosticContext(null), collection.getResourceId(), + feedRange.getRange(), false, null); + }); + + return valueHolderMono.map(partitionKeyRangeListResponse -> { + return toFeedRanges(partitionKeyRangeListResponse); + }); + } + + private static UnmodifiableList> toFeedRanges( + final Utils.ValueHolder> partitionKeyRangeListValueHolder) { + final List partitionKeyRangeList = partitionKeyRangeListValueHolder.v; + if (partitionKeyRangeList == null) { + throw new IllegalStateException("PartitionKeyRange list cannot be null"); + } + + final List> feedRanges = new ArrayList>(); + partitionKeyRangeList.forEach(pkRange -> { + feedRanges.add(pkRange.toRange()); + }); + + final UnmodifiableList> feedRangesResult = + (UnmodifiableList>)UnmodifiableList.unmodifiableList(feedRanges); + + return feedRangesResult; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java index ad7129114b64c..d2d9c65d6015c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java @@ -3,24 +3,61 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.RxDocumentServiceRequest; +import com.azure.cosmos.implementation.routing.Range; + +import java.util.Map; + +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; final class FeedRangeRxDocumentServiceRequestPopulatorVisitor extends GenericFeedRangeVisitor { + public final static FeedRangeRxDocumentServiceRequestPopulatorVisitor SINGLETON = + new FeedRangeRxDocumentServiceRequestPopulatorVisitor(); + + private FeedRangeRxDocumentServiceRequestPopulatorVisitor() + { + } + @Override public void visit(FeedRangeEpk feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { - // TODO fabianm - Implement + + checkNotNull(feedRange, "'feedRange' must not be null"); + checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); + + final Map properties = rxDocumentServiceRequest.getProperties(); + + // In case EPK has already been set by compute + if (properties.containsKey(EpkRequestPropertyConstants.START_EPK_STRING)) { + return; + } + + final Range range = feedRange.getRange(); + + properties.put(EpkRequestPropertyConstants.END_EPK_STRING, range.getMax()); + properties.put(EpkRequestPropertyConstants.START_EPK_STRING, range.getMin()); } @Override public void visit(FeedRangePartitionKeyRange feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { - // TODO fabianm - Implement + + checkNotNull(feedRange, "'feedRange' must not be null"); + checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); + + rxDocumentServiceRequest.routeTo(feedRange.getPartitionKeyRangeIdentity()); } @Override public void visit(FeedRangePartitionKey feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { - // TODO fabianm - Implement + checkNotNull(feedRange, "'feedRange' must not be null"); + checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); + + rxDocumentServiceRequest.getHeaders().put( + HttpConstants.HttpHeaders.PARTITION_KEY, + feedRange.getPartitionKeyInternal().toJson()); + rxDocumentServiceRequest.setPartitionKeyInternal(feedRange.getPartitionKeyInternal()); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java index d30aec45745a9..fcde4efd9335e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/CompositeContinuationToken.java @@ -85,7 +85,7 @@ public Range getRange() { * @param token * the token to set */ - private void setToken(String token) { + public void setToken(String token) { BridgeInternal.setProperty(this, TokenPropertyName, token); } @@ -93,7 +93,7 @@ private void setToken(String token) { * @param range * the range to set */ - private void setRange(Range range) { + public void setRange(Range range) { /* TODO: Don't stringify the range */ BridgeInternal.setProperty(this, RangePropertyName, range.toString()); } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/RetryContextOnDiagnosticTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/RetryContextOnDiagnosticTest.java index 9e0e52126cf14..ed1ffddf597ba 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/RetryContextOnDiagnosticTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/RetryContextOnDiagnosticTest.java @@ -17,6 +17,7 @@ import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.RxDocumentServiceResponse; import com.azure.cosmos.implementation.RxStoreModel; +import com.azure.cosmos.implementation.ShouldRetryResult; import com.azure.cosmos.implementation.TestConfigurations; import com.azure.cosmos.implementation.directconnectivity.AddressSelector; import com.azure.cosmos.implementation.directconnectivity.StoreResponse; @@ -251,7 +252,7 @@ public Mono shouldRetry(Exception e) { if (noRetry) { return Mono.just(ShouldRetryResult.noRetry()); } - return Mono.just(IRetryPolicy.ShouldRetryResult.retryAfter(Duration.ofSeconds(2))); + return Mono.just(ShouldRetryResult.retryAfter(Duration.ofSeconds(2))); } @Override diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientRetryPolicyTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientRetryPolicyTest.java index 397dc88d8ee5c..5f57719b74def 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientRetryPolicyTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientRetryPolicyTest.java @@ -41,7 +41,7 @@ public void networkFailureOnRead() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() @@ -76,7 +76,7 @@ public void tcpNetworkFailureOnRead() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); if (i < 2) { validateSuccess(shouldRetry, ShouldRetryValidator.builder() @@ -114,7 +114,7 @@ public void networkFailureOnWrite() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() .shouldRetry(false) @@ -146,7 +146,7 @@ public void tcpNetworkFailureOnWrite() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); // We don't want to retry writes on network failure with non retriable exception validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() @@ -167,7 +167,7 @@ public void tcpNetworkFailureOnWrite() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); // We want to retry writes on network failure with retriable exception if (i < 2) { validateSuccess(shouldRetry, ShouldRetryValidator.builder() @@ -205,7 +205,7 @@ public void networkFailureOnUpsert() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() .shouldRetry(false) @@ -236,7 +236,7 @@ public void tcpNetworkFailureOnUpsert() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); // We don't want to retry writes on network failure with non retriable exception validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() @@ -266,7 +266,7 @@ public void networkFailureOnDelete() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() .shouldRetry(false) @@ -297,7 +297,7 @@ public void tcpNetworkFailureOnDelete() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); // We don't want to retry writes on network failure with non retriable exception validateSuccess(shouldRetry, ShouldRetryValidator.builder() .nullException() @@ -330,7 +330,7 @@ public void httpNetworkFailureOnQueryPlan() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); if (i < 3) { validateSuccess(shouldRetry, ShouldRetryValidator.builder() @@ -372,7 +372,7 @@ public void httpNetworkFailureOnAddressRefresh() throws Exception { clientRetryPolicy.onBeforeSendRequest(dsr); for (int i = 0; i < 10; i++) { - Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); + Mono shouldRetry = clientRetryPolicy.shouldRetry(cosmosException); if (i < 3) { validateSuccess(shouldRetry, ShouldRetryValidator.builder() @@ -407,7 +407,7 @@ public void onBeforeSendRequestNotInvoked() { OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); - Mono shouldRetry = clientRetryPolicy.shouldRetry(exception); + Mono shouldRetry = clientRetryPolicy.shouldRetry(exception); validateSuccess(shouldRetry, ShouldRetryValidator.builder() .withException(exception) .shouldRetry(false) @@ -416,16 +416,16 @@ public void onBeforeSendRequestNotInvoked() { Mockito.verifyZeroInteractions(endpointManager); } - public static void validateSuccess(Mono single, + public static void validateSuccess(Mono single, ShouldRetryValidator validator) { validateSuccess(single, validator, TIMEOUT); } - public static void validateSuccess(Mono single, + public static void validateSuccess(Mono single, ShouldRetryValidator validator, long timeout) { - TestSubscriber testSubscriber = new TestSubscriber<>(); + TestSubscriber testSubscriber = new TestSubscriber<>(); single.flux().subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java index 0797ba34fffdd..06f5a6513428f 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RenameCollectionAwareClientRetryPolicyTest.java @@ -14,7 +14,6 @@ import static com.azure.cosmos.implementation.ClientRetryPolicyTest.validateSuccess; import static com.azure.cosmos.implementation.TestUtils.mockDiagnosticsClientContext; import static org.assertj.core.api.Assertions.assertThat; -import static com.azure.cosmos.implementation.TestUtils.mockDiagnosticsClientContext; public class RenameCollectionAwareClientRetryPolicyTest { @@ -39,7 +38,7 @@ public void onBeforeSendRequestNotInvoked() { OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); - Mono shouldRetry = + Mono shouldRetry = renameCollectionAwareClientRetryPolicy.shouldRetry(exception); validateSuccess(shouldRetry, ShouldRetryValidator.builder() .withException(exception) @@ -67,7 +66,7 @@ public void shouldRetryWithNotFoundStatusCode() { NotFoundException notFoundException = new NotFoundException(); - Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy + Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy .shouldRetry(notFoundException); validateSuccess(singleShouldRetry, ShouldRetryValidator.builder() .withException(notFoundException) @@ -101,7 +100,7 @@ public void shouldRetryWithNotFoundStatusCodeAndReadSessionNotAvailableSubStatus Mockito.when(rxClientCollectionCache.resolveCollectionAsync(BridgeInternal.getMetaDataDiagnosticContext(request.requestContext.cosmosDiagnostics), request)).thenReturn(Mono.just(new Utils.ValueHolder<>(documentCollection))); - Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy + Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy .shouldRetry(notFoundException); validateSuccess(singleShouldRetry, ShouldRetryValidator.builder() .nullException() @@ -128,9 +127,9 @@ public void shouldRetryWithGenericException() { request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); renameCollectionAwareClientRetryPolicy.onBeforeSendRequest(request); - Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy + Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy .shouldRetry(new BadRequestException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isFalse(); } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RetryUtilsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RetryUtilsTest.java index da35a459cec37..de77eb4e6117d 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RetryUtilsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/RetryUtilsTest.java @@ -2,7 +2,6 @@ // Licensed under the MIT License. package com.azure.cosmos.implementation; -import com.azure.cosmos.implementation.IRetryPolicy.ShouldRetryResult; import com.azure.cosmos.implementation.directconnectivity.AddressSelector; import com.azure.cosmos.implementation.directconnectivity.StoreResponse; import com.azure.cosmos.implementation.directconnectivity.StoreResponseValidator; diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ShouldRetryValidator.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ShouldRetryValidator.java index 4eab46b76dc9a..757f754b045f1 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ShouldRetryValidator.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ShouldRetryValidator.java @@ -13,7 +13,7 @@ */ public interface ShouldRetryValidator { - void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult); + void validate(ShouldRetryResult shouldRetryResult); static Builder builder() { return new Builder(); @@ -26,7 +26,7 @@ public ShouldRetryValidator build() { return new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { for (ShouldRetryValidator validator : validators) { validator.validate(shouldRetryResult); } @@ -38,7 +38,7 @@ public Builder nullException() { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.exception).isNull(); } }); @@ -49,7 +49,7 @@ public Builder hasException() { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.exception).isNotNull(); } }); @@ -60,7 +60,7 @@ public Builder exceptionOfType(Class klass) { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.exception).isNotNull(); assertThat(shouldRetryResult.exception).isInstanceOf(klass); } @@ -72,7 +72,7 @@ public Builder withException(FailureValidator failureValidator) { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.exception).isNotNull(); failureValidator.validate(shouldRetryResult.exception); } @@ -84,7 +84,7 @@ public Builder withException(Exception exception) { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.exception).isNotNull(); assertThat(shouldRetryResult.exception).isEqualTo(exception); } @@ -96,7 +96,7 @@ public Builder shouldRetry(boolean value) { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.shouldRetry).isEqualTo(value); } }); @@ -108,7 +108,7 @@ public Builder backOfTime(Duration backOfTime) { validators.add(new ShouldRetryValidator() { @Override - public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + public void validate(ShouldRetryResult shouldRetryResult) { assertThat(shouldRetryResult.backOffTime).isEqualTo(backOfTime); } }); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java index a28721a7b8b13..8a49e736c7865 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java @@ -8,7 +8,6 @@ import com.azure.cosmos.implementation.BadRequestException; import com.azure.cosmos.implementation.GoneException; import com.azure.cosmos.implementation.HttpConstants; -import com.azure.cosmos.implementation.IRetryPolicy; import com.azure.cosmos.implementation.InvalidPartitionException; import com.azure.cosmos.implementation.OperationType; import com.azure.cosmos.implementation.PartitionIsMigratingException; @@ -16,6 +15,7 @@ import com.azure.cosmos.implementation.RequestTimeoutException; import com.azure.cosmos.implementation.ResourceType; import com.azure.cosmos.implementation.RxDocumentServiceRequest; +import com.azure.cosmos.implementation.ShouldRetryResult; import com.azure.cosmos.implementation.guava25.base.Supplier; import org.testng.annotations.Test; import reactor.core.publisher.Mono; @@ -41,9 +41,9 @@ public void shouldRetryReadWithGoneException() { OperationType.Read, ResourceType.Document); GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(new GoneException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isTrue(); assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(1); @@ -91,9 +91,9 @@ public void shouldRetryNotYetFlushedWriteWithGoneException() { return goneExceptionForNotYetFlushedRequest; }; - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(goneExceptionForNotYetFlushedRequestSupplier.get()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isTrue(); assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(1); @@ -141,9 +141,9 @@ public void shouldNotRetryFlushedWriteWithGoneExceptionButForceAddressRefresh() }; GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(goneExceptionForFlushedRequestSupplier.get()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isFalse(); assertThat(shouldRetryResult.policyArg).isNotNull(); @@ -163,9 +163,9 @@ public void shouldNotRetryRequestTimeoutException() { ResourceType.Document); GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(new RequestTimeoutException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isFalse(); assertThat(shouldRetryResult.policyArg).isNull(); @@ -196,9 +196,9 @@ public void shouldRetryWithPartitionIsMigratingException() { OperationType.Read, ResourceType.Document); GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(new PartitionIsMigratingException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isTrue(); assertThat(request.forceCollectionRoutingMapRefresh).isTrue(); assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); @@ -214,9 +214,9 @@ public void shouldRetryWithInvalidPartitionException() { OperationType.Read, ResourceType.Document); GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(new InvalidPartitionException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isTrue(); assertThat(request.requestContext.quorumSelectedLSN).isEqualTo(-1); assertThat(request.requestContext.resolvedPartitionKeyRange).isNull(); @@ -242,9 +242,9 @@ public void shouldRetryWithPartitionKeyRangeIsSplittingException() { OperationType.Read, ResourceType.Document); GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(new PartitionKeyRangeIsSplittingException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isTrue(); assertThat(request.forcePartitionKeyRangeRefresh).isTrue(); assertThat(request.requestContext.resolvedPartitionKeyRange).isNull(); @@ -263,9 +263,9 @@ public void shouldRetryWithGenericException() { OperationType.Read, ResourceType.Document); GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(new BadRequestException()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isFalse(); } From 46662e06209505e511f01bd53027c378a375d28f Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 12 Nov 2020 00:19:01 +0000 Subject: [PATCH 03/17] Adding public surface area --- .../azure/cosmos/CosmosAsyncContainer.java | 12 ++++ .../com/azure/cosmos/CosmosContainer.java | 20 ++++++ .../implementation/AsyncDocumentClient.java | 9 +++ .../implementation/RxDocumentClientImpl.java | 62 +++++++++++++++++++ .../feedranges/FeedRangeAsyncVisitor.java | 6 +- .../FeedRangeAsyncVisitorWithArg.java | 6 +- ...> FeedRangeCompositeContinuationImpl.java} | 20 +++--- .../feedranges/FeedRangeContinuation.java | 3 +- ...ntServiceRequestPopulatorVisitorImpl.java} | 6 +- .../FeedRangeContinuationVisitor.java | 2 +- ...eedRangeEpk.java => FeedRangeEpkImpl.java} | 10 +-- ...ey.java => FeedRangePartitionKeyImpl.java} | 4 +- ...dRangePartitionKeyRangeExtractorImpl.java} | 10 +-- ...va => FeedRangePartitionKeyRangeImpl.java} | 4 +- ...ntServiceRequestPopulatorVisitorImpl.java} | 14 ++--- .../feedranges/FeedRangeTransformer.java | 6 +- .../feedranges/FeedRangeVisitor.java | 6 +- .../feedranges/GenericFeedRangeVisitor.java | 6 +- .../com/azure/cosmos/models/FeedRange.java | 2 +- .../main/java/com/azure/cosmos/util/Beta.java | 2 + .../GoneAndRetryWithRetryPolicyTest.java | 4 +- 21 files changed, 159 insertions(+), 55 deletions(-) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangeCompositeContinuation.java => FeedRangeCompositeContinuationImpl.java} (94%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java => FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java} (91%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangeEpk.java => FeedRangeEpkImpl.java} (92%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangePartitionKey.java => FeedRangePartitionKeyImpl.java} (96%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangePartitionKeyRangeExtractor.java => FeedRangePartitionKeyRangeExtractorImpl.java} (93%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangePartitionKeyRange.java => FeedRangePartitionKeyRangeImpl.java} (95%) rename sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/{FeedRangeRxDocumentServiceRequestPopulatorVisitor.java => FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java} (80%) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java index 8d0a3a151c696..c60ba9162f743 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java @@ -25,6 +25,7 @@ import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKey; @@ -1124,4 +1125,15 @@ private Mono replaceThroughputInternal(Mono> getFeedRanges() { + return this.getDatabase().getDocClientWrapper().getFeedRanges(getLink()); + } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java index 2b7379f1cc533..4726664f2a7f7 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java @@ -10,6 +10,7 @@ import com.azure.cosmos.models.CosmosContainerResponse; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.models.SqlQuerySpec; @@ -556,4 +557,23 @@ private CosmosPagedIterable getCosmosPagedIterable(CosmosPagedFlux cos return UtilBridgeInternal.createCosmosPagedIterable(cosmosPagedFlux); } + /** + * Obtains a list of {@link FeedRange} that can be used to parallelize Feed + * operations. + * + * @return An unmodifiable list of {@link FeedRange} + */ + @Beta(Beta.SinceVersion.NextMinorRelease) + public List getFeedRanges() { + try { + return asyncContainer.getFeedRanges().block(); + } catch (Exception ex) { + final Throwable throwable = Exceptions.unwrap(ex); + if (throwable instanceof CosmosException) { + throw (CosmosException) throwable; + } else { + throw ex; + } + } + } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java index 2837d33269c75..32098f0f6c699 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/AsyncDocumentClient.java @@ -10,6 +10,7 @@ import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.models.CosmosItemIdentity; import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.PartitionKey; import com.azure.cosmos.models.SqlQuerySpec; @@ -668,6 +669,14 @@ Flux> queryDocumentChangeFeed(String collectionLink, */ Flux> readPartitionKeyRanges(String collectionLink, CosmosQueryRequestOptions options); + /** + * Gets the feed ranges of a container. + * + * @param collectionLink the link to the parent document collection. + * @return a {@link List} of @{link FeedRange} containing the feed ranges of a container. + */ + Mono> getFeedRanges(String collectionLink); + /** * Creates a stored procedure. *

diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java index a2178ea4376c0..d1a3f3013839f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java @@ -11,6 +11,7 @@ import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosDiagnostics; import com.azure.cosmos.DirectConnectionConfig; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.batch.BatchResponseParser; import com.azure.cosmos.implementation.batch.ServerBatchRequest; import com.azure.cosmos.implementation.batch.SinglePartitionKeyServerBatchRequest; @@ -26,6 +27,7 @@ import com.azure.cosmos.implementation.directconnectivity.ServerStoreModel; import com.azure.cosmos.implementation.directconnectivity.StoreClient; import com.azure.cosmos.implementation.directconnectivity.StoreClientFactory; +import com.azure.cosmos.implementation.feedranges.FeedRangePartitionKeyRangeImpl; import com.azure.cosmos.implementation.http.HttpClient; import com.azure.cosmos.implementation.http.HttpClientConfig; import com.azure.cosmos.implementation.http.HttpHeaders; @@ -40,8 +42,10 @@ import com.azure.cosmos.implementation.routing.PartitionKeyAndResourceTokenPair; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.PartitionKeyInternalHelper; +import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.models.CosmosItemIdentity; import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.FeedResponse; import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKey; @@ -94,6 +98,9 @@ public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorizationTokenProvider, CpuListener, DiagnosticsClientContext { private static final AtomicInteger activeClientsCnt = new AtomicInteger(0); private static final AtomicInteger clientIdGenerator = new AtomicInteger(0); + private static final Range RANGE_INCLUDING_ALL_PARTITION_KEY_RANGES = new Range( + PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, + PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey, true, false); private static final String DUMMY_SQL_QUERY = "this is dummy and only used in creating " + "ParallelDocumentQueryExecutioncontext, but not used"; @@ -3634,4 +3641,59 @@ private static SqlQuerySpec createLogicalPartitionScanQuerySpec( return new SqlQuerySpec(queryStringBuilder.toString(), parameters); } + + @Override + public Mono> getFeedRanges(String collectionLink) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create( + this, + OperationType.Query, + ResourceType.Document, + collectionLink, + null); // This should not go to backend + Mono> collectionObs = collectionCache.resolveCollectionAsync(null, + request); + + return collectionObs.flatMap(documentCollectionResourceResponse -> { + final DocumentCollection collection = documentCollectionResourceResponse.v; + if (collection == null) { + throw new IllegalStateException("Collection cannot be null"); + } + + Mono>> valueHolderMono = partitionKeyRangeCache + .tryGetOverlappingRangesAsync( + BridgeInternal.getMetaDataDiagnosticContext(request.requestContext.cosmosDiagnostics), + collection.getResourceId(), RANGE_INCLUDING_ALL_PARTITION_KEY_RANGES, true, null); + + return valueHolderMono.map(partitionKeyRangeListResponse -> { + return toFeedRanges(partitionKeyRangeListResponse); + }); + }); + } + + private static List toFeedRanges( + Utils.ValueHolder> partitionKeyRangeListValueHolder) { + final List partitionKeyRangeList = partitionKeyRangeListValueHolder.v; + if (partitionKeyRangeList == null) { + throw new IllegalStateException("PartitionKeyRange list cannot be null"); + } + + List feedRanges = new ArrayList(); + partitionKeyRangeList.forEach(pkRange -> { + feedRanges.add(toFeedRange(pkRange)); + }); + + UnmodifiableList feedRangesResult = (UnmodifiableList) Collections + .unmodifiableList(feedRanges); + + return feedRangesResult; + } + + private static FeedRange toFeedRange(PartitionKeyRange pkRange) { + return new FeedRangePartitionKeyRangeImpl(pkRange.getId()); + } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java index ce9431448966b..e2f8f4c1a5f64 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java @@ -6,9 +6,9 @@ import reactor.core.publisher.Mono; abstract class FeedRangeAsyncVisitor { - public abstract Mono visitAsync(FeedRangePartitionKey feedRange); + public abstract Mono visitAsync(FeedRangePartitionKeyImpl feedRange); - public abstract Mono visitAsync(FeedRangePartitionKeyRange feedRange); + public abstract Mono visitAsync(FeedRangePartitionKeyRangeImpl feedRange); - public abstract Mono visitAsync(FeedRangeEpk feedRange); + public abstract Mono visitAsync(FeedRangeEpkImpl feedRange); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java index dc765746fd601..408db1da7aaed 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java @@ -6,9 +6,9 @@ import reactor.core.publisher.Mono; abstract class FeedRangeAsyncVisitorWithArg { - public abstract Mono visitAsync(FeedRangePartitionKey feedRange, TArg argument); + public abstract Mono visitAsync(FeedRangePartitionKeyImpl feedRange, TArg argument); - public abstract Mono visitAsync(FeedRangePartitionKeyRange feedRange, TArg argument); + public abstract Mono visitAsync(FeedRangePartitionKeyRangeImpl feedRange, TArg argument); - public abstract Mono visitAsync(FeedRangeEpk feedRange, TArg argument); + public abstract Mono visitAsync(FeedRangeEpkImpl feedRange, TArg argument); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java similarity index 94% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java index c3b7ae6316578..3335e9f9d4e47 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java @@ -30,7 +30,7 @@ * FeedRangeContinuation using Composite Continuation Tokens and split proof. * It uses a breath-first approach to transverse Composite Continuation Tokens. */ -final class FeedRangeCompositeContinuation extends FeedRangeContinuation { +final class FeedRangeCompositeContinuationImpl extends FeedRangeContinuation { private final static ShouldRetryResult RETRY = ShouldRetryResult.retryAfter(Duration.ZERO); private final static ShouldRetryResult NO_RETRY = ShouldRetryResult.noRetry(); @@ -39,13 +39,13 @@ final class FeedRangeCompositeContinuation extends FeedRangeContinuation { private CompositeContinuationToken currentToken; private String initialNoResultsRange; - private FeedRangeCompositeContinuation(String containerRid, FeedRangeInternal feedRange) { + private FeedRangeCompositeContinuationImpl(String containerRid, FeedRangeInternal feedRange) { super(containerRid, feedRange); this.compositeContinuationTokens = new LinkedList(); } - public FeedRangeCompositeContinuation( + public FeedRangeCompositeContinuationImpl( String containerRid, FeedRangeInternal feedRange, List> ranges) { @@ -53,7 +53,7 @@ public FeedRangeCompositeContinuation( this(containerRid, feedRange, ranges, null); } - public FeedRangeCompositeContinuation( + public FeedRangeCompositeContinuationImpl( String containerRid, FeedRangeInternal feedRange, List> ranges, @@ -69,7 +69,7 @@ public FeedRangeCompositeContinuation( for (Range range : ranges) { this.compositeContinuationTokens.add( - FeedRangeCompositeContinuation.createCompositeContinuationTokenForRange( + FeedRangeCompositeContinuationImpl.createCompositeContinuationTokenForRange( range.getMin(), range.getMax(), continuation) @@ -82,12 +82,12 @@ public FeedRangeCompositeContinuation( /** * Used for deserializtion only */ - public static FeedRangeCompositeContinuation createFromDeserializedTokens( + public static FeedRangeCompositeContinuationImpl createFromDeserializedTokens( String containerRid, FeedRangeInternal feedRange, List deserializedTokens) { - FeedRangeCompositeContinuation thisPtr = new FeedRangeCompositeContinuation(containerRid, feedRange); + FeedRangeCompositeContinuationImpl thisPtr = new FeedRangeCompositeContinuationImpl(containerRid, feedRange); checkNotNull(deserializedTokens, "'deserializedTokens' must not be null"); @@ -124,14 +124,14 @@ public String getContinuation() { @Override public FeedRangeInternal getFeedRange() { - if (!(this.feedRange instanceof FeedRangeEpk)) + if (!(this.feedRange instanceof FeedRangeEpkImpl)) { return this.feedRange; } if (this.currentToken != null) { - return new FeedRangeEpk(this.currentToken.getRange()); + return new FeedRangeEpkImpl(this.currentToken.getRange()); } return null; @@ -271,7 +271,7 @@ public static FeedRangeContinuation parse(final String jsonString) throws IOExce final ObjectMapper mapper = Utils.getSimpleObjectMapper(); - return mapper.readValue(jsonString, FeedRangeCompositeContinuation.class); + return mapper.readValue(jsonString, FeedRangeCompositeContinuationImpl.class); } private static CompositeContinuationToken createCompositeContinuationTokenForRange( diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java index 43baf1e0520c3..e4f450b431b59 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java @@ -3,7 +3,6 @@ package com.azure.cosmos.implementation.feedranges; -import com.azure.cosmos.CosmosAsyncContainer; import com.azure.cosmos.implementation.RxDocumentClientImpl; import com.azure.cosmos.implementation.RxDocumentServiceResponse; import com.azure.cosmos.implementation.ShouldRetryResult; @@ -45,7 +44,7 @@ public FeedRangeInternal getFeedRange() { public static FeedRangeContinuation tryParse(String toStringValue) { - return FeedRangeCompositeContinuation.tryParse(toStringValue); + return FeedRangeCompositeContinuationImpl.tryParse(toStringValue); } public abstract ShouldRetryResult handleChangeFeedNotModified( diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java similarity index 91% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java index a7dce884c5544..419ad526eae9d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java @@ -11,12 +11,12 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; -final class FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor extends FeedRangeContinuationVisitor { +final class FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl extends FeedRangeContinuationVisitor { private final RxDocumentServiceRequest request; private final BiConsumer fillContinuation; - public FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor( + public FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl( RxDocumentServiceRequest request, BiConsumer fillContinuation) { checkNotNull(request, "'request' must not be null"); @@ -27,7 +27,7 @@ public FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitor( } @Override - public void visit(FeedRangeCompositeContinuation feedRangeCompositeContinuation) { + public void visit(FeedRangeCompositeContinuationImpl feedRangeCompositeContinuation) { checkNotNull(feedRangeCompositeContinuation, "'feedRangeCompositeContinuation' must not be null"); final Map properties = this.request.getProperties(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java index 669e13b6f2019..5e625668a2177 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationVisitor.java @@ -4,5 +4,5 @@ package com.azure.cosmos.implementation.feedranges; abstract class FeedRangeContinuationVisitor { - public abstract void visit(FeedRangeCompositeContinuation feedRangeCompositeContinuation); + public abstract void visit(FeedRangeCompositeContinuationImpl feedRangeCompositeContinuation); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java similarity index 92% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index 6f6b3045a7519..92163826c8d0d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpk.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -16,14 +16,14 @@ import java.util.ArrayList; import java.util.List; -final class FeedRangeEpk extends FeedRangeInternal { - private static final FeedRangeEpk fullRangeEPK = - new FeedRangeEpk(PartitionKeyInternalHelper.FullRange); +final class FeedRangeEpkImpl extends FeedRangeInternal { + private static final FeedRangeEpkImpl fullRangeEPK = + new FeedRangeEpkImpl(PartitionKeyInternalHelper.FullRange); private final Range range; private final UnmodifiableList> rangeList; - public FeedRangeEpk(final Range range) { + public FeedRangeEpkImpl(final Range range) { if (range == null) { throw new NullPointerException("range"); } @@ -39,7 +39,7 @@ public Range getRange() { return this.range; } - public static FeedRangeEpk ForFullRange() { + public static FeedRangeEpkImpl ForFullRange() { return fullRangeEPK; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java similarity index 96% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index a4fae18c6418f..49854a69700aa 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKey.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -14,10 +14,10 @@ import java.util.ArrayList; import java.util.Collections; -final class FeedRangePartitionKey extends FeedRangeInternal { +final class FeedRangePartitionKeyImpl extends FeedRangeInternal { private final PartitionKeyInternal partitionKey; - public FeedRangePartitionKey(PartitionKeyInternal partitionKey) { + public FeedRangePartitionKeyImpl(PartitionKeyInternal partitionKey) { if (partitionKey == null) { throw new NullPointerException("partitionKey"); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java similarity index 93% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java index 9b80b75943409..e91248aa85345 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java @@ -19,12 +19,12 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; -final class FeedRangePartitionKeyRangeExtractor extends FeedRangeAsyncVisitor>> { +final class FeedRangePartitionKeyRangeExtractorImpl extends FeedRangeAsyncVisitor>> { private final RxDocumentClientImpl client; private final String collectionLink; - public FeedRangePartitionKeyRangeExtractor( + public FeedRangePartitionKeyRangeExtractorImpl( RxDocumentClientImpl client, String collectionLink) { @@ -36,7 +36,7 @@ public FeedRangePartitionKeyRangeExtractor( } @Override - public Mono>> visitAsync(FeedRangePartitionKey feedRange) { + public Mono>> visitAsync(FeedRangePartitionKeyImpl feedRange) { final RxPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); final Mono> collectionResponseObservable = this.client @@ -51,7 +51,7 @@ public Mono>> visitAsync(FeedRangePartitionKey feedRange) { } @Override - public Mono>> visitAsync(FeedRangePartitionKeyRange feedRange) { + public Mono>> visitAsync(FeedRangePartitionKeyRangeImpl feedRange) { final RxPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); final Mono> collectionResponseObservable = this.client @@ -65,7 +65,7 @@ public Mono>> visitAsync(FeedRangePartitionKeyRange feedRange } @Override - public Mono>> visitAsync(FeedRangeEpk feedRange) { + public Mono>> visitAsync(FeedRangeEpkImpl feedRange) { final RxPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); final Mono> collectionResponseObservable = this.client diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java similarity index 95% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index f2978cbf9b036..f5bb39b3ac04a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRange.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -15,11 +15,11 @@ import java.util.ArrayList; import java.util.Collections; -final class FeedRangePartitionKeyRange extends FeedRangeInternal { +public final class FeedRangePartitionKeyRangeImpl extends FeedRangeInternal { private final String partitionKeyRangeId; private final PartitionKeyRangeIdentity partitionKeyRangeIdentity; - public FeedRangePartitionKeyRange(final String partitionKeyRangeId) { + public FeedRangePartitionKeyRangeImpl(final String partitionKeyRangeId) { if (partitionKeyRangeId == null) { throw new NullPointerException("partitionKeyRangeId"); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java similarity index 80% rename from sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java rename to sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java index d2d9c65d6015c..53bda322289df 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java @@ -11,18 +11,18 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; -final class FeedRangeRxDocumentServiceRequestPopulatorVisitor +final class FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl extends GenericFeedRangeVisitor { - public final static FeedRangeRxDocumentServiceRequestPopulatorVisitor SINGLETON = - new FeedRangeRxDocumentServiceRequestPopulatorVisitor(); + public final static FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl SINGLETON = + new FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl(); - private FeedRangeRxDocumentServiceRequestPopulatorVisitor() + private FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl() { } @Override - public void visit(FeedRangeEpk feedRange, + public void visit(FeedRangeEpkImpl feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { checkNotNull(feedRange, "'feedRange' must not be null"); @@ -42,7 +42,7 @@ public void visit(FeedRangeEpk feedRange, } @Override - public void visit(FeedRangePartitionKeyRange feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { + public void visit(FeedRangePartitionKeyRangeImpl feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { checkNotNull(feedRange, "'feedRange' must not be null"); checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); @@ -51,7 +51,7 @@ public void visit(FeedRangePartitionKeyRange feedRange, RxDocumentServiceRequest } @Override - public void visit(FeedRangePartitionKey feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { + public void visit(FeedRangePartitionKeyImpl feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { checkNotNull(feedRange, "'feedRange' must not be null"); checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java index ea045a8cac82f..0c0a20a887582 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeTransformer.java @@ -4,9 +4,9 @@ package com.azure.cosmos.implementation.feedranges; abstract class FeedRangeTransformer { - public abstract TResult visit(FeedRangePartitionKey feedRange); + public abstract TResult visit(FeedRangePartitionKeyImpl feedRange); - public abstract TResult visit(FeedRangePartitionKeyRange feedRange); + public abstract TResult visit(FeedRangePartitionKeyRangeImpl feedRange); - public abstract TResult visit(FeedRangeEpk feedRange); + public abstract TResult visit(FeedRangeEpkImpl feedRange); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java index d41e406bde240..f6c142c30e294 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeVisitor.java @@ -4,9 +4,9 @@ package com.azure.cosmos.implementation.feedranges; abstract class FeedRangeVisitor { - public abstract void visit(FeedRangeEpk feedRange); + public abstract void visit(FeedRangeEpkImpl feedRange); - public abstract void visit(FeedRangePartitionKeyRange feedRange); + public abstract void visit(FeedRangePartitionKeyRangeImpl feedRange); - public abstract void visit(FeedRangePartitionKey feedRange); + public abstract void visit(FeedRangePartitionKeyImpl feedRange); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java index f523581d432ad..d91e81de8ba61 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/GenericFeedRangeVisitor.java @@ -4,9 +4,9 @@ package com.azure.cosmos.implementation.feedranges; abstract class GenericFeedRangeVisitor { - public abstract void visit(FeedRangeEpk feedRange, TInput input); + public abstract void visit(FeedRangeEpkImpl feedRange, TInput input); - public abstract void visit(FeedRangePartitionKeyRange feedRange, TInput input); + public abstract void visit(FeedRangePartitionKeyRangeImpl feedRange, TInput input); - public abstract void visit(FeedRangePartitionKey feedRange, TInput input); + public abstract void visit(FeedRangePartitionKeyImpl feedRange, TInput input); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java index 3f369f6212576..b25d3f2b923fe 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java @@ -8,7 +8,7 @@ import java.io.IOException; -@Beta(Beta.SinceVersion.V4_9_0) +@Beta(Beta.SinceVersion.NextMinorRelease) public interface FeedRange { /** * Creates a range from a previously obtained string representation. diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java index ac92720730665..078bf9a3d7cd8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java @@ -50,5 +50,7 @@ public enum SinceVersion { V4_8_0, /** v4.9.0 */ V4_9_0, + /** NextMinorRelease */ + NextMinorRelease, } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java index 363cd49a045d4..6019bbda468c3 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicyTest.java @@ -173,9 +173,9 @@ public void shouldRetryFlushedWriteWithGoneExceptionFromService() { return goneExceptionForFlushedRequest; }; - Mono singleShouldRetry = goneAndRetryWithRetryPolicy + Mono singleShouldRetry = goneAndRetryWithRetryPolicy .shouldRetry(goneExceptionForFlushedRequestSupplier.get()); - IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); assertThat(shouldRetryResult.shouldRetry).isTrue(); assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(1); From 03617a4b6c865db61b15eab54e644d2247028bbe Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Thu, 12 Nov 2020 23:13:26 +0000 Subject: [PATCH 04/17] Adding FeedRange unit tests --- .../implementation/PartitionKeyRange.java | 6 +- .../feedranges/FeedRangeTest.java | 154 ++++++++++++++++++ 2 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java index 20b44c57dc52e..8483b9b4ca8c1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/PartitionKeyRange.java @@ -74,16 +74,18 @@ public String getMinInclusive() { return super.getString("minInclusive"); } - public void setMinInclusive(String minInclusive) { + public PartitionKeyRange setMinInclusive(String minInclusive) { BridgeInternal.setProperty(this, "minInclusive", minInclusive); + return this; } public String getMaxExclusive() { return super.getString("maxExclusive"); } - public void setMaxExclusive(String maxExclusive) { + public PartitionKeyRange setMaxExclusive(String maxExclusive) { BridgeInternal.setProperty(this, "maxExclusive", maxExclusive); + return this; } public Range toRange() { diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java new file mode 100644 index 0000000000000..760ed07fc6388 --- /dev/null +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -0,0 +1,154 @@ +package com.azure.cosmos.implementation.feedranges; + +import com.azure.cosmos.implementation.IRoutingMapProvider; +import com.azure.cosmos.implementation.MetadataDiagnosticsContext; +import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.Utils; +import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.routing.PartitionKeyInternal; +import com.azure.cosmos.implementation.routing.PartitionKeyInternalUtils; +import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.PartitionKeyDefinition; +import org.mockito.Mockito; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Mockito.when; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; + +public class FeedRangeTest { + + @Test(groups = "unit") + public void feedRangeEPK_Range() { + Range range = new Range<>("AA", "BB", true, false); + FeedRangeEpkImpl feedRangeEPK = new FeedRangeEpkImpl(range); + assertThat(range).isEqualTo(feedRangeEPK.getRange()); + } + + @Test(groups = "unit") + public void feedRangePK_PK() + { + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); + FeedRangePartitionKeyImpl feedRangePartitionKey = new FeedRangePartitionKeyImpl(partitionKey); + assertThat(partitionKey).isEqualTo(feedRangePartitionKey.getPartitionKeyInternal()); + } + + @Test(groups = "unit") + public void FeedRangePKRangeId_PKRange() + { + String pkRangeId = UUID.randomUUID().toString(); + FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = new FeedRangePartitionKeyRangeImpl(pkRangeId); + assertThat(pkRangeId).isEqualTo(feedRangePartitionKeyRange.getPartitionKeyRangeId()); + } + + @Test(groups = "unit") + public void FeedRangeEPK_GetEffectiveRangesAsync() + { + Range range = new Range<>("AA", "BB", true, false); + FeedRangeEpkImpl FeedRangeEpk = new FeedRangeEpkImpl(range); + + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + StepVerifier + .create( + FeedRangeEpk.getEffectiveRangesAsync( + routingMapProviderMock, + null, + null)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + assertThat(new ArrayList<>(r).get(0)) + .hasSize(1) + .contains(range); + }) + .verifyComplete(); + } + + @Test(groups = "unit") + public void FeedRangePK_GetEffectiveRangesAsync() + { + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.getPaths().add("/id"); + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); + FeedRangePartitionKeyImpl feedRangePartitionKey = new FeedRangePartitionKeyImpl(partitionKey); + Range range = Range.getPointRange( + partitionKey.getEffectivePartitionKeyString(partitionKey, partitionKeyDefinition)); + + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + StepVerifier + .create( + feedRangePartitionKey.getEffectiveRangesAsync( + routingMapProviderMock, + null, + partitionKeyDefinition)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + assertThat(new ArrayList<>(r).get(0)) + .hasSize(1) + .contains(range); + }) + .verifyComplete(); + } + + @Test(groups = "unit") + public void FeedRangePKRangeId_GetEffectiveRangesAsync() + { + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive("AA") + .setMaxExclusive("BB"); + + FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetPartitionKeyRangeByIdAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(partitionKeyRange.getId()), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(partitionKeyRange))); + + StepVerifier + .create( + feedRangePartitionKeyRange.getEffectiveRangesAsync( + routingMapProviderMock, null, null)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + UnmodifiableList> ranges = new ArrayList<>(r).get(0); + assertThat(ranges).hasSize(1); + Range range = ranges.get(0); + assertThat(range).isNotNull(); + assertThat(range.getMin()).isEqualTo(partitionKeyRange.getMinInclusive()); + assertThat(range.getMax()).isEqualTo(partitionKeyRange.getMaxExclusive()); + assertThat(range.getMin()).isEqualTo(partitionKeyRange.toRange().getMin()); + assertThat(range.getMax()).isEqualTo(partitionKeyRange.toRange().getMax()); + }) + .verifyComplete(); + + Mockito + .verify(routingMapProviderMock, Mockito.times(1)) + .tryGetPartitionKeyRangeByIdAsync( + null, + null, + partitionKeyRange.getId(), + false, + null); + } +} From b7de6b34f68bcc4fedc8188773f4ee7c664eb276 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 00:03:45 +0000 Subject: [PATCH 05/17] Adding test FeedRangePKRangeId_GetEffectiveRangesAsync_Refresh --- .../FeedRangePartitionKeyRangeImpl.java | 17 ++++++- .../feedranges/FeedRangeTest.java | 51 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index f5bb39b3ac04a..ce0eef742737d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -3,8 +3,10 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.GoneException; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; import com.azure.cosmos.implementation.Utils.ValueHolder; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; @@ -68,7 +70,7 @@ public Mono>> getEffectiveRangesAsync( false, null) .flatMap((pkRangeHolder) -> { - if (pkRangeHolder == null) { + if (pkRangeHolder.v == null) { return routingMapProvider.tryGetPartitionKeyRangeByIdAsync( null, containerRid, @@ -78,6 +80,19 @@ public Mono>> getEffectiveRangesAsync( } else { return Mono.just(pkRangeHolder); } + }) + .flatMap((pkRangeHolder) -> { + if (pkRangeHolder.v == null) { + return Mono.error( + new PartitionKeyRangeGoneException( + String.format( + "The PartitionKeyRangeId: \"%s\" is not valid for the current container %s .", + partitionKeyRangeId, + containerRid) + )); + } else { + return Mono.just(pkRangeHolder); + } }); return getPkRangeTask.flatMap((pkRangeHolder) -> { diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 760ed07fc6388..c92cd3cd82941 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -151,4 +151,55 @@ public void FeedRangePKRangeId_GetEffectiveRangesAsync() false, null); } + + @Test(groups = "unit") + public void FeedRangePKRangeId_GetEffectiveRangesAsync_Refresh() + { + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive("AA") + .setMaxExclusive("BB"); + + FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetPartitionKeyRangeByIdAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(partitionKeyRange.getId()), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(partitionKeyRange))); + + StepVerifier + .create( + feedRangePartitionKeyRange.getEffectiveRangesAsync( + routingMapProviderMock, null, null)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + UnmodifiableList> ranges = new ArrayList<>(r).get(0); + assertThat(ranges).hasSize(1); + Range range = ranges.get(0); + assertThat(range).isNotNull(); + assertThat(range.getMin()).isEqualTo(partitionKeyRange.getMinInclusive()); + assertThat(range.getMax()).isEqualTo(partitionKeyRange.getMaxExclusive()); + assertThat(range.getMin()).isEqualTo(partitionKeyRange.toRange().getMin()); + assertThat(range.getMax()).isEqualTo(partitionKeyRange.toRange().getMax()); + }) + .verifyComplete(); + + Mockito + .verify(routingMapProviderMock, Mockito.times(2)) + .tryGetPartitionKeyRangeByIdAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(partitionKeyRange.getId()), + anyBoolean(), + anyMapOf(String.class, Object.class)); + } } From 4095bc5bc318c7c11178e3b2db19f9cec27d5637 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 00:33:45 +0000 Subject: [PATCH 06/17] Adding test FeedRangePKRangeId_GetEffectiveRangesAsync_Null --- .../feedranges/FeedRangeTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index c92cd3cd82941..2f4a9697220a4 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -1,8 +1,10 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.MetadataDiagnosticsContext; import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; @@ -202,4 +204,40 @@ public void FeedRangePKRangeId_GetEffectiveRangesAsync_Refresh() anyBoolean(), anyMapOf(String.class, Object.class)); } + + @Test(groups = "unit") + public void FeedRangePKRangeId_GetEffectiveRangesAsync_Null() + { + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive("AA") + .setMaxExclusive("BB"); + + FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetPartitionKeyRangeByIdAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(partitionKeyRange.getId()), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))); + + StepVerifier + .create( + feedRangePartitionKeyRange.getEffectiveRangesAsync( + routingMapProviderMock, null, null)) + .recordWith(ArrayList::new) + .expectErrorSatisfies((e) -> { + assertThat(e).isInstanceOf(PartitionKeyRangeGoneException.class); + PartitionKeyRangeGoneException pkGoneException = (PartitionKeyRangeGoneException)e; + assertThat(pkGoneException.getSubStatusCode()) + .isEqualTo(HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE); + }) + .verify(); + } } From 8e864bef45a1eac6c7b4dfec191e44975b7abf1c Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 10:18:21 +0000 Subject: [PATCH 07/17] Adding test feedRangeEPK_getPartitionKeyRangesAsync --- .../feedranges/FeedRangeTest.java | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 2f4a9697220a4..a2e505946f25f 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -17,6 +17,7 @@ import reactor.test.StepVerifier; import java.util.ArrayList; +import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +46,7 @@ public void feedRangePK_PK() } @Test(groups = "unit") - public void FeedRangePKRangeId_PKRange() + public void feedRangePKRangeId_PKRange() { String pkRangeId = UUID.randomUUID().toString(); FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = new FeedRangePartitionKeyRangeImpl(pkRangeId); @@ -53,7 +54,7 @@ public void FeedRangePKRangeId_PKRange() } @Test(groups = "unit") - public void FeedRangeEPK_GetEffectiveRangesAsync() + public void feedRangeEPK_getEffectiveRangesAsync() { Range range = new Range<>("AA", "BB", true, false); FeedRangeEpkImpl FeedRangeEpk = new FeedRangeEpkImpl(range); @@ -77,7 +78,7 @@ public void FeedRangeEPK_GetEffectiveRangesAsync() } @Test(groups = "unit") - public void FeedRangePK_GetEffectiveRangesAsync() + public void feedRangePK_getEffectiveRangesAsync() { PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); partitionKeyDefinition.getPaths().add("/id"); @@ -105,7 +106,7 @@ public void FeedRangePK_GetEffectiveRangesAsync() } @Test(groups = "unit") - public void FeedRangePKRangeId_GetEffectiveRangesAsync() + public void feedRangePKRangeId_getEffectiveRangesAsync() { String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() @@ -155,7 +156,7 @@ public void FeedRangePKRangeId_GetEffectiveRangesAsync() } @Test(groups = "unit") - public void FeedRangePKRangeId_GetEffectiveRangesAsync_Refresh() + public void feedRangePKRangeId_getEffectiveRangesAsync_Refresh() { String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() @@ -206,7 +207,7 @@ public void FeedRangePKRangeId_GetEffectiveRangesAsync_Refresh() } @Test(groups = "unit") - public void FeedRangePKRangeId_GetEffectiveRangesAsync_Null() + public void feedRangePKRangeId_getEffectiveRangesAsync_Null() { String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() @@ -240,4 +241,54 @@ public void FeedRangePKRangeId_GetEffectiveRangesAsync_Null() }) .verify(); } + + @Test(groups = "unit") + public void feedRangeEPK_getPartitionKeyRangesAsync() + { + Range range = new Range<>("AA", "BB", true, false); + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive(range.getMin()) + .setMaxExclusive(range.getMax()); + + List pkRanges = new ArrayList<>(); + pkRanges.add(partitionKeyRange); + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetOverlappingRangesAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(range), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); + + FeedRangeEpkImpl feedRangeEpk = new FeedRangeEpkImpl(range); + StepVerifier + .create( + feedRangeEpk.getPartitionKeyRangesAsync( + routingMapProviderMock, + null, + null)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + UnmodifiableList response = new ArrayList<>(r).get(0); + assertThat(response) + .hasSize(1) + .contains(partitionKeyRange.getId()); + }) + .verifyComplete(); + + Mockito + .verify(routingMapProviderMock, Mockito.times(1)) + .tryGetOverlappingRangesAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(range), + eq(false), + anyMapOf(String.class, Object.class)); + } } From 4ebd7cb8fdd916954a2d419dba6fbe056c1186be Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 10:27:33 +0000 Subject: [PATCH 08/17] Adding test feedRangePK_getPartitionKeyRangesAsync --- .../feedranges/FeedRangeTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index a2e505946f25f..79f1a3578f8b2 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -291,4 +291,49 @@ public void feedRangeEPK_getPartitionKeyRangesAsync() eq(false), anyMapOf(String.class, Object.class)); } + + @Test(groups = "unit") + public void feedRangePK_getPartitionKeyRangesAsync() + { + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.getPaths().add("/id"); + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); + + Range range = new Range<>("AA", "BB", true, false); + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive(range.getMin()) + .setMaxExclusive(range.getMax()); + List pkRanges = new ArrayList<>(); + pkRanges.add(partitionKeyRange); + + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetOverlappingRangesAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + any(Range.class), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); + + FeedRangePartitionKeyImpl feedRangPartitionKey = new FeedRangePartitionKeyImpl(partitionKey); + StepVerifier + .create( + feedRangPartitionKey.getPartitionKeyRangesAsync( + routingMapProviderMock, + null, + partitionKeyDefinition)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + UnmodifiableList response = new ArrayList<>(r).get(0); + assertThat(response) + .hasSize(1) + .contains(partitionKeyRange.getId()); + }) + .verifyComplete(); + } } From 2e6eb7967c8d4a1a7ea37a2389ef6770d031a6ea Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 10:32:17 +0000 Subject: [PATCH 09/17] Adding test feedRangePKRangeId_getPartitionKeyRangesAsync --- .../feedranges/FeedRangeTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 79f1a3578f8b2..d44d87678c448 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -336,4 +336,36 @@ public void feedRangePK_getPartitionKeyRangesAsync() }) .verifyComplete(); } + + @Test(groups = "unit") + public void feedRangePKRangeId_getPartitionKeyRangesAsync() + { + Range range = new Range<>("AA", "BB", true, false); + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive(range.getMin()) + .setMaxExclusive(range.getMax()); + + FeedRangePartitionKeyRangeImpl feedRangPartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + StepVerifier + .create( + feedRangPartitionKeyRange.getPartitionKeyRangesAsync( + routingMapProviderMock, + null, + null)) + .recordWith(ArrayList::new) + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + UnmodifiableList response = new ArrayList<>(r).get(0); + assertThat(response) + .hasSize(1) + .contains(partitionKeyRange.getId()); + }) + .verifyComplete(); + } } From dc4c66c3402f26d1e2342ae7d02d0facadc74d62 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 11:22:22 +0000 Subject: [PATCH 10/17] Adding request visitor unit tests --- .../RxDocumentServiceRequest.java | 14 ++++ .../feedranges/FeedRangeEpkImpl.java | 9 ++ .../feedranges/FeedRangeInternal.java | 2 + .../feedranges/FeedRangePartitionKeyImpl.java | 9 ++ .../FeedRangePartitionKeyRangeImpl.java | 9 ++ ...entServiceRequestPopulatorVisitorImpl.java | 2 +- .../feedranges/FeedRangeTest.java | 82 +++++++++++++++++++ 7 files changed, 126 insertions(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java index 365f336412fe5..2cffdde72de55 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java @@ -1019,6 +1019,20 @@ public Map getProperties() { return this.properties; } + /** + * Gets the request properties. + * + * @return the request properties. + */ + public Map getPropertiesOrThrow() { + if (this.properties == null) { + throw new IllegalStateException( + "Only requests with properties (request options) can be used when using feed ranges"); + } + + return this.properties; + } + private static Map getProperties(Object options) { if (options == null) { return null; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index 92163826c8d0d..b2b511ecd4d1e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -52,6 +52,15 @@ public void accept(final FeedRangeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(GenericFeedRangeVisitor visitor, TInput input) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this, input); + } + @Override public Mono acceptAsync(final FeedRangeAsyncVisitor visitor) { if (visitor == null) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java index 91771bd29d0eb..7e0247eb42669 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -18,6 +18,8 @@ public abstract class FeedRangeInternal extends JsonSerializable implements FeedRange { public abstract void accept(FeedRangeVisitor visitor); + public abstract void accept(GenericFeedRangeVisitor visitor, TInput input); + public abstract Mono acceptAsync(FeedRangeAsyncVisitor visitor); public static FeedRangeInternal convert(final FeedRange feedRange) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index 49854a69700aa..ac15568d54b60 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -38,6 +38,15 @@ public void accept(FeedRangeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(GenericFeedRangeVisitor visitor, TInput input) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this, input); + } + @Override public Mono acceptAsync(FeedRangeAsyncVisitor visitor) { if (visitor == null) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index ce0eef742737d..ec33f92ecc964 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -47,6 +47,15 @@ public void accept(final FeedRangeVisitor visitor) { visitor.visit(this); } + @Override + public void accept(GenericFeedRangeVisitor visitor, TInput input) { + if (visitor == null) { + throw new NullPointerException("visitor"); + } + + visitor.visit(this, input); + } + @Override public Mono acceptAsync(final FeedRangeAsyncVisitor visitor) { if (visitor == null) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java index 53bda322289df..dee731f2ea236 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java @@ -28,7 +28,7 @@ public void visit(FeedRangeEpkImpl feedRange, checkNotNull(feedRange, "'feedRange' must not be null"); checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); - final Map properties = rxDocumentServiceRequest.getProperties(); + final Map properties = rxDocumentServiceRequest.getPropertiesOrThrow(); // In case EPK has already been set by compute if (properties.containsKey(EpkRequestPropertyConstants.START_EPK_STRING)) { diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index d44d87678c448..6bb29c904df04 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -3,8 +3,12 @@ import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.MetadataDiagnosticsContext; +import com.azure.cosmos.implementation.OperationType; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; +import com.azure.cosmos.implementation.RequestOptions; +import com.azure.cosmos.implementation.ResourceType; +import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; @@ -17,10 +21,13 @@ import reactor.test.StepVerifier; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.UUID; +import static com.azure.cosmos.implementation.TestUtils.mockDiagnosticsClientContext; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.ThrowableAssert.catchThrowableOfType; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyMapOf; @@ -368,4 +375,79 @@ public void feedRangePKRangeId_getPartitionKeyRangesAsync() }) .verifyComplete(); } + + @Test(groups = "unit") + public void feedRangeEPK_RequestVisitor_ThrowsWhenNoPropertiesAvailable() { + Range range = new Range("AA", "BB", true, false); + FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); + RxDocumentServiceRequest request = createMockRequest(false); + assertThat(catchThrowableOfType(() -> { + feedRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + }, + IllegalStateException.class)).isNotNull(); + } + + @Test(groups = "unit") + public void feedRangeEPK_RequestVisitor() { + Range range = new Range("AA", "BB", true, false); + FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); + RxDocumentServiceRequest request = createMockRequest(true); + feedRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + assertThat(request.getProperties()).hasSize(2); + assertThat(request.getProperties().get(EpkRequestPropertyConstants.START_EPK_STRING)) + .isNotNull() + .isEqualTo("AA"); + assertThat(request.getProperties().get(EpkRequestPropertyConstants.END_EPK_STRING)) + .isNotNull() + .isEqualTo("BB"); + } + + @Test(groups = "unit") + public void feedRangePKRangeId_RequestVisitor() { + Range range = new Range<>("AA", "BB", true, false); + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive(range.getMin()) + .setMaxExclusive(range.getMax()); + + FeedRangePartitionKeyRangeImpl feedRangPartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + + RxDocumentServiceRequest request = createMockRequest(true); + feedRangPartitionKeyRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + assertThat(request.getPartitionKeyRangeIdentity()).isNotNull(); + } + + @Test(groups = "unit") + public void feedRangePK_RequestVisitor() { + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); + FeedRangePartitionKeyImpl feedRangePartitionKey = new FeedRangePartitionKeyImpl(partitionKey); + RxDocumentServiceRequest request = createMockRequest(true); + feedRangePartitionKey.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + assertThat(request.getPartitionKeyInternal()).isNotNull(); + assertThat(request.getPartitionKeyInternal().toJson()) + .isNotNull() + .isEqualTo(request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY)); + } + + private static RxDocumentServiceRequest createMockRequest(boolean hasProperties) { + RequestOptions requestOptions = new RequestOptions(); + + if (hasProperties) { + requestOptions.setProperties(new HashMap<>()); + } + + return RxDocumentServiceRequest.create( + mockDiagnosticsClientContext(), + OperationType.Read, + ResourceType.Document, + "/dbs/db/colls/col/docs/docId", + null, + requestOptions); + } } From 0ef3170e6b938b585218cb1274af297221a488a5 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 14:20:56 +0000 Subject: [PATCH 11/17] Finishing FeedRange tests --- .../cosmos/implementation/Constants.java | 5 ++ .../feedranges/FeedRangeEpkImpl.java | 15 +++++ .../feedranges/FeedRangeInternal.java | 59 +++++++++++++++-- .../feedranges/FeedRangePartitionKeyImpl.java | 12 ++++ .../FeedRangePartitionKeyRangeImpl.java | 14 +++++ .../com/azure/cosmos/models/FeedRange.java | 18 +----- .../feedranges/FeedRangeTest.java | 63 ++++++++++++++++--- 7 files changed, 157 insertions(+), 29 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java index 1437feb49a2bb..f1559ce97622e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java @@ -201,6 +201,11 @@ public static final class Properties { public static final String KeyWrapMetadataValue = "value"; public static final String EncryptedInfo = "_ei"; + // Feed Ranges + public static final String RANGE = "Range"; + public static final String FEED_RANGE_PARTITION_KEY = "PartitionKey"; + public static final String FEED_RANGE_PARTITION_KEY_RANGE_ID = "PKRangeId"; + } public static final class UrlEncodingInfo { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index b2b511ecd4d1e..cd3089a4c746e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -3,19 +3,25 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternalHelper; import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKeyDefinition; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Mono; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static com.azure.cosmos.BridgeInternal.setProperty; + final class FeedRangeEpkImpl extends FeedRangeInternal { private static final FeedRangeEpkImpl fullRangeEPK = new FeedRangeEpkImpl(PartitionKeyInternalHelper.FullRange); @@ -120,4 +126,13 @@ public String toJsonString() { public String toString() { return this.range.toString(); } + + public void populatePropertyBag() { + super.populatePropertyBag(); + + if (this.range != null) { + ModelBridgeInternal.populatePropertyBag(this.range); + setProperty(this, Constants.Properties.RANGE, this.range); + } + } } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java index 7e0247eb42669..647e38a1a8579 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -3,19 +3,24 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.JsonSerializable; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; +import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.PartitionKeyDefinition; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Mono; import java.io.IOException; public abstract class FeedRangeInternal extends JsonSerializable implements FeedRange { + public abstract void accept(FeedRangeVisitor visitor); public abstract void accept(GenericFeedRangeVisitor visitor, TInput input); @@ -31,12 +36,34 @@ public static FeedRangeInternal convert(final FeedRange feedRange) { return (FeedRangeInternal)feedRange; } + String json = feedRange.toJsonString(); + return fromJsonString(json); + } + + /** + * Creates a range from a previously obtained string representation. + * + * @param json A string representation of a feed range + * @return A feed range + */ + public static FeedRangeInternal fromJsonString(String json) { + FeedRangeInternal parsedRange; + try { - return tryParse(feedRange.toJsonString()); - } catch (final IOException ioError) { + parsedRange = FeedRangeInternal.tryParse(json); + } catch (IOException e) { throw new IllegalArgumentException( - "Invalid/unknown FeedRange instance.", ioError); + String.format("Unable to parse JSON %s", json), e); } + + if (parsedRange == null) { + throw new IllegalArgumentException( + String.format( + "The provided string '%s' does not represent any known format.", + json)); + } + + return parsedRange; } public abstract Mono>> getEffectiveRangesAsync( @@ -57,13 +84,35 @@ public String toJsonString() { @Override public abstract String toString(); + public void populatePropertyBag() { + super.populatePropertyBag(); + } + public static FeedRangeInternal tryParse(final String jsonString) throws IOException { if (jsonString == null) { throw new NullPointerException("jsonString"); } final ObjectMapper mapper = Utils.getSimpleObjectMapper(); - final FeedRangeInternal feedRange = mapper.readValue(jsonString, FeedRangeInternal.class); - return feedRange; + JsonNode rootNode = mapper.readTree(jsonString); + + JsonNode rangeNode = rootNode.get(Constants.Properties.RANGE); + if (rangeNode != null && rangeNode.isObject()) { + Range range = new Range<>((ObjectNode)rangeNode); + return new FeedRangeEpkImpl(range); + } + + JsonNode pkNode = rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY); + if (pkNode != null && pkNode.isArray()) { + PartitionKeyInternal pk = mapper.convertValue(pkNode, PartitionKeyInternal.class); + return new FeedRangePartitionKeyImpl(pk); + } + + JsonNode pkRangeIdNode = rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID); + if (pkRangeIdNode != null && pkRangeIdNode.isTextual()) { + return new FeedRangePartitionKeyRangeImpl(pkRangeIdNode.asText()); + } + + return null; } } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index ac15568d54b60..9fa6a6b4976a4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -3,17 +3,21 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.Collections; +import static com.azure.cosmos.BridgeInternal.setProperty; + final class FeedRangePartitionKeyImpl extends FeedRangeInternal { private final PartitionKeyInternal partitionKey; @@ -110,6 +114,14 @@ public String toString() { return this.partitionKey.toJson(); } + public void populatePropertyBag() { + super.populatePropertyBag(); + + if (this.partitionKey != null) { + setProperty(this, Constants.Properties.FEED_RANGE_PARTITION_KEY, this.partitionKey); + } + } + private static Mono tryGetRangeByEffectivePartitionKey( IRoutingMapProvider routingMapProvider, String containerRid, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index ec33f92ecc964..dbdc7f9d3d555 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.feedranges; +import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.GoneException; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; @@ -17,6 +18,8 @@ import java.util.ArrayList; import java.util.Collections; +import static com.azure.cosmos.BridgeInternal.setProperty; + public final class FeedRangePartitionKeyRangeImpl extends FeedRangeInternal { private final String partitionKeyRangeId; private final PartitionKeyRangeIdentity partitionKeyRangeIdentity; @@ -135,4 +138,15 @@ public String toJsonString() { public String toString() { return this.partitionKeyRangeId; } + + public void populatePropertyBag() { + super.populatePropertyBag(); + + if (this.partitionKeyRangeId != null) { + setProperty( + this, + Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID, + this.partitionKeyRangeId); + } + } } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java index b25d3f2b923fe..78e41e964b9b0 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java @@ -17,23 +17,7 @@ public interface FeedRange { * @return A feed range */ public static FeedRange fromJsonString(String json) { - FeedRange parsedRange = null; - - try { - parsedRange = FeedRangeInternal.tryParse(json); - } catch (IOException e) { - throw new IllegalArgumentException( - String.format("Unable to parse JSON %s", json), e); - } - - if (parsedRange == null) { - throw new IllegalArgumentException( - String.format( - "The provided string '%s' does not represent any known format.", - json)); - } - - return parsedRange; + return FeedRangeInternal.fromJsonString(json); } public String toJsonString(); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 6bb29c904df04..6b15dc686f5cf 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -14,6 +14,7 @@ import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.PartitionKeyInternalUtils; import com.azure.cosmos.implementation.routing.Range; +import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.PartitionKeyDefinition; import org.mockito.Mockito; import org.testng.annotations.Test; @@ -320,7 +321,7 @@ public void feedRangePK_getPartitionKeyRangesAsync() routingMapProviderMock.tryGetOverlappingRangesAsync( any(MetadataDiagnosticsContext.class), anyString(), - any(Range.class), + any(), anyBoolean(), anyMapOf(String.class, Object.class))) .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); @@ -378,19 +379,17 @@ public void feedRangePKRangeId_getPartitionKeyRangesAsync() @Test(groups = "unit") public void feedRangeEPK_RequestVisitor_ThrowsWhenNoPropertiesAvailable() { - Range range = new Range("AA", "BB", true, false); + Range range = new Range<>("AA", "BB", true, false); FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); RxDocumentServiceRequest request = createMockRequest(false); - assertThat(catchThrowableOfType(() -> { - feedRange.accept( - FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); - }, + assertThat(catchThrowableOfType(() -> feedRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request), IllegalStateException.class)).isNotNull(); } @Test(groups = "unit") public void feedRangeEPK_RequestVisitor() { - Range range = new Range("AA", "BB", true, false); + Range range = new Range<>("AA", "BB", true, false); FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); RxDocumentServiceRequest request = createMockRequest(true); feedRange.accept( @@ -435,6 +434,54 @@ public void feedRangePK_RequestVisitor() { .isEqualTo(request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY)); } + @Test(groups = "unit") + public void feedRangeEPK_toJsonFromJson() { + Range range = new Range<>("AA", "BB", true, false); + FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); + String representation = feedRange.toJson(); + assertThat(FeedRange.fromJsonString(representation)) + .isNotNull() + .isInstanceOf(FeedRangeEpkImpl.class); + FeedRangeEpkImpl feedRangeDeserialized = (FeedRangeEpkImpl)FeedRange.fromJsonString(representation); + String representationAfterDeserialization = feedRangeDeserialized.toJson(); + assertThat(representationAfterDeserialization).isEqualTo(representation); + assertThat(feedRangeDeserialized.getRange()).isNotNull(); + assertThat(feedRangeDeserialized.getRange().getMin()) + .isNotNull() + .isEqualTo(range.getMin()); + assertThat(feedRangeDeserialized.getRange().getMax()) + .isNotNull() + .isEqualTo(range.getMax()); + } + + @Test(groups = "unit") + public void feedRangePK_toJsonFromJson() { + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); + FeedRangePartitionKeyImpl feedRange = new FeedRangePartitionKeyImpl(partitionKey); + String representation = feedRange.toJson(); + assertThat(FeedRange.fromJsonString(representation)) + .isNotNull() + .isInstanceOf(FeedRangePartitionKeyImpl.class); + FeedRangePartitionKeyImpl feedRangeDeserialized = + (FeedRangePartitionKeyImpl)FeedRange.fromJsonString(representation); + String representationAfterDeserialization = feedRangeDeserialized.toJson(); + assertThat(representationAfterDeserialization).isEqualTo(representation); + } + + @Test(groups = "unit") + public void feedRangePKRangeId_toJsonFromJson() { + String pkRangeId = UUID.randomUUID().toString(); + FeedRangePartitionKeyRangeImpl feedRange = new FeedRangePartitionKeyRangeImpl(pkRangeId); + String representation = feedRange.toJson(); + assertThat(FeedRange.fromJsonString(representation)) + .isNotNull() + .isInstanceOf(FeedRangePartitionKeyRangeImpl.class); + FeedRangePartitionKeyRangeImpl feedRangeDeserialized = + (FeedRangePartitionKeyRangeImpl)FeedRange.fromJsonString(representation); + String representationAfterDeserialization = feedRangeDeserialized.toJson(); + assertThat(representationAfterDeserialization).isEqualTo(representation); + } + private static RxDocumentServiceRequest createMockRequest(boolean hasProperties) { RequestOptions requestOptions = new RequestOptions(); @@ -450,4 +497,6 @@ private static RxDocumentServiceRequest createMockRequest(boolean hasProperties) null, requestOptions); } + + } From ae9dd96891d3cc3ef381aaba31b9695cde1f2f9c Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 14:48:00 +0000 Subject: [PATCH 12/17] Cleanup and prettifying --- .../azure/cosmos/CosmosAsyncContainer.java | 2 +- .../com/azure/cosmos/CosmosContainer.java | 2 +- .../RxDocumentServiceRequest.java | 9 - .../implementation/ShouldRetryResult.java | 24 +-- .../FeedRangeAsyncVisitorWithArg.java | 3 +- .../FeedRangeCompositeContinuationImpl.java | 179 +++++++++--------- .../feedranges/FeedRangeContinuation.java | 3 +- ...entServiceRequestPopulatorVisitorImpl.java | 2 +- .../feedranges/FeedRangeEpkImpl.java | 44 ++--- .../feedranges/FeedRangeInternal.java | 13 +- .../feedranges/FeedRangePartitionKeyImpl.java | 24 ++- ...edRangePartitionKeyRangeExtractorImpl.java | 18 +- .../FeedRangePartitionKeyRangeImpl.java | 32 ++-- ...entServiceRequestPopulatorVisitorImpl.java | 9 +- .../com/azure/cosmos/models/FeedRange.java | 2 +- .../main/java/com/azure/cosmos/util/Beta.java | 2 - .../feedranges/FeedRangeTest.java | 6 +- 17 files changed, 175 insertions(+), 199 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java index c60ba9162f743..f0fa6e06e781d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosAsyncContainer.java @@ -1132,7 +1132,7 @@ ItemDeserializer getItemDeserializer() { * * @return An unmodifiable list of {@link FeedRange} */ - @Beta(Beta.SinceVersion.NextMinorRelease) + @Beta(Beta.SinceVersion.V4_9_0) public Mono> getFeedRanges() { return this.getDatabase().getDocClientWrapper().getFeedRanges(getLink()); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java index 4726664f2a7f7..2785afb5669de 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/CosmosContainer.java @@ -563,7 +563,7 @@ private CosmosPagedIterable getCosmosPagedIterable(CosmosPagedFlux cos * * @return An unmodifiable list of {@link FeedRange} */ - @Beta(Beta.SinceVersion.NextMinorRelease) + @Beta(Beta.SinceVersion.V4_9_0) public List getFeedRanges() { try { return asyncContainer.getFeedRanges().block(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java index 2cffdde72de55..e95c443dd7d67 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentServiceRequest.java @@ -1010,15 +1010,6 @@ public void dispose() { this.isDisposed = true; } - /** - * Gets the request properties. - * - * @return the request properties. - */ - public Map getProperties() { - return this.properties; - } - /** * Gets the request properties. * diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java index 0030cbe2a62e9..bf32924e9cded 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java @@ -8,8 +8,8 @@ public class ShouldRetryResult { /// public final Duration backOffTime; public final Exception exception; - public boolean shouldRetry; public final Quadruple policyArg; + public boolean shouldRetry; private ShouldRetryResult(Duration dur, Exception e, boolean shouldRetry, Quadruple policyArg) { @@ -19,17 +19,6 @@ private ShouldRetryResult(Duration dur, Exception e, boolean shouldRetry, this.policyArg = policyArg; } - public static ShouldRetryResult retryAfter(Duration dur) { - Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); - return new ShouldRetryResult(dur, null, true, null); - } - - public static ShouldRetryResult retryAfter(Duration dur, - Quadruple policyArg) { - Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); - return new ShouldRetryResult(dur, null, true, policyArg); - } - public static ShouldRetryResult error(Exception e) { Utils.checkNotNullOrThrow(e, "exception", "cannot be null"); return new ShouldRetryResult(null, e, false, null); @@ -47,6 +36,17 @@ public static ShouldRetryResult noRetry(Quadruple policyArg) { + Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); + return new ShouldRetryResult(dur, null, true, policyArg); + } + + public static ShouldRetryResult retryAfter(Duration dur) { + Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); + return new ShouldRetryResult(dur, null, true, null); + } + public void throwIfDoneTrying(Exception capturedException) throws Exception { if (this.shouldRetry) { return; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java index 408db1da7aaed..67a239aa70f12 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java @@ -8,7 +8,8 @@ abstract class FeedRangeAsyncVisitorWithArg { public abstract Mono visitAsync(FeedRangePartitionKeyImpl feedRange, TArg argument); - public abstract Mono visitAsync(FeedRangePartitionKeyRangeImpl feedRange, TArg argument); + public abstract Mono visitAsync(FeedRangePartitionKeyRangeImpl feedRange, + TArg argument); public abstract Mono visitAsync(FeedRangeEpkImpl feedRange, TArg argument); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java index 3335e9f9d4e47..3f4ab2a963ed5 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java @@ -32,19 +32,12 @@ */ final class FeedRangeCompositeContinuationImpl extends FeedRangeContinuation { - private final static ShouldRetryResult RETRY = ShouldRetryResult.retryAfter(Duration.ZERO); private final static ShouldRetryResult NO_RETRY = ShouldRetryResult.noRetry(); - + private final static ShouldRetryResult RETRY = ShouldRetryResult.retryAfter(Duration.ZERO); private final Queue compositeContinuationTokens; private CompositeContinuationToken currentToken; private String initialNoResultsRange; - private FeedRangeCompositeContinuationImpl(String containerRid, FeedRangeInternal feedRange) { - super(containerRid, feedRange); - - this.compositeContinuationTokens = new LinkedList(); - } - public FeedRangeCompositeContinuationImpl( String containerRid, FeedRangeInternal feedRange, @@ -73,64 +66,33 @@ public FeedRangeCompositeContinuationImpl( range.getMin(), range.getMax(), continuation) - ); + ); } this.currentToken = this.getCompositeContinuationTokens().peek(); } - /** - * Used for deserializtion only - */ - public static FeedRangeCompositeContinuationImpl createFromDeserializedTokens( - String containerRid, - FeedRangeInternal feedRange, - List deserializedTokens) { - - FeedRangeCompositeContinuationImpl thisPtr = new FeedRangeCompositeContinuationImpl(containerRid, feedRange); - - checkNotNull(deserializedTokens, "'deserializedTokens' must not be null"); - - if (deserializedTokens.size() == 0) { - throw new IllegalArgumentException("'deserializedTokens' must not be empty"); - } - - for (CompositeContinuationToken token : deserializedTokens) { - thisPtr.compositeContinuationTokens.add(token); - } - - thisPtr.currentToken = thisPtr.getCompositeContinuationTokens().peek(); + private FeedRangeCompositeContinuationImpl(String containerRid, FeedRangeInternal feedRange) { + super(containerRid, feedRange); - return thisPtr; + this.compositeContinuationTokens = new LinkedList<>(); } public Queue getCompositeContinuationTokens() { - return getCompositeContinuationTokens(); + return compositeContinuationTokens; } public CompositeContinuationToken getCurrentToken() { return this.currentToken; } - @Override - public String getContinuation() { - CompositeContinuationToken tokenSnapshot = this.currentToken; - if (tokenSnapshot == null) { - return null; - } - - return tokenSnapshot.getToken(); - } - @Override public FeedRangeInternal getFeedRange() { - if (!(this.feedRange instanceof FeedRangeEpkImpl)) - { + if (!(this.feedRange instanceof FeedRangeEpkImpl)) { return this.feedRange; } - if (this.currentToken != null) - { + if (this.currentToken != null) { return new FeedRangeEpkImpl(this.currentToken.getRange()); } @@ -138,14 +100,13 @@ public FeedRangeInternal getFeedRange() { } @Override - public String toString() { - try { - return Utils.getSimpleObjectMapper().writeValueAsString(this); - } catch (final IOException e) { - throw new IllegalArgumentException( - "Unable serialize the composite FeedRange continuation token into a JSON string", - e); + public String getContinuation() { + CompositeContinuationToken tokenSnapshot = this.currentToken; + if (tokenSnapshot == null) { + return null; } + + return tokenSnapshot.getToken(); } @Override @@ -228,10 +189,10 @@ public Mono handleSplitAsync(final RxDocumentClientImpl clien nSubStatus = Integers.tryParse(valueSubStatus); } - final Boolean partitionSplit = + final boolean partitionSplit = response.getStatusCode() == HttpConstants.StatusCodes.GONE && nSubStatus != null - && (nSubStatus.intValue() == HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE - || nSubStatus.intValue() == HttpConstants.SubStatusCodes.COMPLETING_SPLIT); + && (nSubStatus == HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE + || nSubStatus == HttpConstants.SubStatusCodes.COMPLETING_SPLIT); if (!partitionSplit) { return Mono.just(NO_RETRY); @@ -244,15 +205,13 @@ public Mono handleSplitAsync(final RxDocumentClientImpl clien this.currentToken.getRange().getMax(), true); - final Mono result = resolvedRangesTask.flatMap(resolvedRanges -> { + return resolvedRangesTask.flatMap(resolvedRanges -> { if (resolvedRanges.v != null && resolvedRanges.v.size() > 0) { this.createChildRanges(resolvedRanges.v); } return Mono.just(RETRY); }); - - return result; } @Override @@ -264,6 +223,30 @@ public void accept(final FeedRangeContinuationVisitor visitor) { visitor.visit(this); } + /** + * Used for deserializtion only + */ + public static FeedRangeCompositeContinuationImpl createFromDeserializedTokens( + String containerRid, + FeedRangeInternal feedRange, + List deserializedTokens) { + + FeedRangeCompositeContinuationImpl thisPtr = + new FeedRangeCompositeContinuationImpl(containerRid, feedRange); + + checkNotNull(deserializedTokens, "'deserializedTokens' must not be null"); + + if (deserializedTokens.size() == 0) { + throw new IllegalArgumentException("'deserializedTokens' must not be empty"); + } + + thisPtr.compositeContinuationTokens.addAll(deserializedTokens); + + thisPtr.currentToken = thisPtr.getCompositeContinuationTokens().peek(); + + return thisPtr; + } + public static FeedRangeContinuation parse(final String jsonString) throws IOException { if (jsonString == null) { throw new NullPointerException("jsonString"); @@ -274,46 +257,21 @@ public static FeedRangeContinuation parse(final String jsonString) throws IOExce return mapper.readValue(jsonString, FeedRangeCompositeContinuationImpl.class); } - private static CompositeContinuationToken createCompositeContinuationTokenForRange( - String minInclusive, - String maxExclusive, - String token) - { - return new CompositeContinuationToken( - token, - new Range(minInclusive, maxExclusive, true, false)); - } - - private static CompositeContinuationToken tryParseAsCompositeContinuationToken( - final String providedContinuation) { - + @Override + public String toString() { try { - final ObjectMapper mapper = Utils.getSimpleObjectMapper(); - - if (providedContinuation.trim().startsWith("[")) { - final List compositeContinuationTokens = Arrays - .asList(mapper.readValue(providedContinuation, - CompositeContinuationToken[].class)); - - if (compositeContinuationTokens != null && compositeContinuationTokens.size() > 0) { - return compositeContinuationTokens.get(0); - } - - return null; - } else if (providedContinuation.trim().startsWith("{")) { - return mapper.readValue(providedContinuation, CompositeContinuationToken.class); - } - - return null; - } catch (final IOException ioError) { - return null; + return Utils.getSimpleObjectMapper().writeValueAsString(this); + } catch (final IOException e) { + throw new IllegalArgumentException( + "Unable serialize the composite FeedRange continuation token into a JSON string", + e); } } private void createChildRanges(final List keyRanges) { final PartitionKeyRange firstRange = keyRanges.get(0); this.currentToken - .setRange(new Range(firstRange.getMinInclusive(), + .setRange(new Range<>(firstRange.getMinInclusive(), firstRange.getMaxExclusive(), true, false)); final CompositeContinuationToken continuationAsComposite = @@ -345,6 +303,15 @@ private void createChildRanges(final List keyRanges) { } } + private static CompositeContinuationToken createCompositeContinuationTokenForRange( + String minInclusive, + String maxExclusive, + String token) { + return new CompositeContinuationToken( + token, + new Range<>(minInclusive, maxExclusive, true, false)); + } + private void moveToNextToken() { final CompositeContinuationToken recentToken = this.compositeContinuationTokens.poll(); if (recentToken.getToken() != null) { @@ -368,6 +335,32 @@ private Mono>> tryGetOverlappingRanges final Boolean forceRefresh) { return partitionKeyRangeCache.tryGetOverlappingRangesAsync(null, this.getContainerRid(), - new Range(min, max, false, true), forceRefresh, null); + new Range<>(min, max, false, true), forceRefresh, null); + } + + private static CompositeContinuationToken tryParseAsCompositeContinuationToken( + final String providedContinuation) { + + try { + final ObjectMapper mapper = Utils.getSimpleObjectMapper(); + + if (providedContinuation.trim().startsWith("[")) { + final List compositeContinuationTokens = Arrays + .asList(mapper.readValue(providedContinuation, + CompositeContinuationToken[].class)); + + if (compositeContinuationTokens.size() > 0) { + return compositeContinuationTokens.get(0); + } + + return null; + } else if (providedContinuation.trim().startsWith("{")) { + return mapper.readValue(providedContinuation, CompositeContinuationToken.class); + } + + return null; + } catch (final IOException ioError) { + return null; + } } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java index e4f450b431b59..c8fdc3ff0a60d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java @@ -42,8 +42,7 @@ public FeedRangeInternal getFeedRange() { public abstract void validateContainer(String containerRid); - public static FeedRangeContinuation tryParse(String toStringValue) - { + public static FeedRangeContinuation tryParse(String toStringValue) { return FeedRangeCompositeContinuationImpl.tryParse(toStringValue); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java index 419ad526eae9d..52bf9883ca9bb 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl.java @@ -30,7 +30,7 @@ public FeedRangeContinuationRxDocumentServiceRequestPopulatorVisitorImpl( public void visit(FeedRangeCompositeContinuationImpl feedRangeCompositeContinuation) { checkNotNull(feedRangeCompositeContinuation, "'feedRangeCompositeContinuation' must not be null"); - final Map properties = this.request.getProperties(); + final Map properties = this.request.getPropertiesOrThrow(); // In case EPK has already been set by compute if (properties.containsKey(EpkRequestPropertyConstants.START_EPK_STRING)) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index cd3089a4c746e..2885954918918 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -12,8 +12,6 @@ import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKeyDefinition; -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import reactor.core.publisher.Mono; import java.io.IOException; @@ -35,7 +33,7 @@ public FeedRangeEpkImpl(final Range range) { } this.range = range; - final ArrayList> temp = new ArrayList>(); + final ArrayList> temp = new ArrayList<>(); temp.add(range); this.rangeList = (UnmodifiableList>)UnmodifiableList.unmodifiableList(temp); @@ -91,24 +89,25 @@ public Mono> getPartitionKeyRangesAsync( final String containerRid, final PartitionKeyDefinition partitionKeyDefinition) { - return routingMapProvider.tryGetOverlappingRangesAsync( - null, - containerRid, - this.range, - false, - null) - .flatMap(pkRangeHolder -> { - final ArrayList rangeList = new ArrayList(); - - if (pkRangeHolder != null) { - final List pkRanges = pkRangeHolder.v; - for (final PartitionKeyRange pkRange : pkRanges) { - rangeList.add(pkRange.getId()); - } - } - - return Mono.just((UnmodifiableList)UnmodifiableList.unmodifiableList(rangeList)); - }); + return routingMapProvider + .tryGetOverlappingRangesAsync( + null, + containerRid, + this.range, + false, + null) + .flatMap(pkRangeHolder -> { + final ArrayList rangeList = new ArrayList<>(); + + if (pkRangeHolder != null) { + final List pkRanges = pkRangeHolder.v; + for (final PartitionKeyRange pkRange : pkRanges) { + rangeList.add(pkRange.getId()); + } + } + + return Mono.just((UnmodifiableList)UnmodifiableList.unmodifiableList(rangeList)); + }); } @Override @@ -117,7 +116,8 @@ public String toJsonString() { return Utils.getSimpleObjectMapper().writeValueAsString(this); } catch (final IOException e) { throw new IllegalArgumentException( - "Unable serialize the feed range token for an extended partition key into a JSON string", + "Unable serialize the feed range token for an extended partition key into a JSON " + + "string", e); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java index 647e38a1a8579..0f444a714fb60 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -76,16 +76,16 @@ public abstract Mono> getPartitionKeyRangesAsync( String containerRid, PartitionKeyDefinition partitionKeyDefinition); - @Override - public String toJsonString() { - return this.toJson(); + public void populatePropertyBag() { + super.populatePropertyBag(); } @Override public abstract String toString(); - public void populatePropertyBag() { - super.populatePropertyBag(); + @Override + public String toJsonString() { + return this.toJson(); } public static FeedRangeInternal tryParse(final String jsonString) throws IOException { @@ -108,7 +108,8 @@ public static FeedRangeInternal tryParse(final String jsonString) throws IOExcep return new FeedRangePartitionKeyImpl(pk); } - JsonNode pkRangeIdNode = rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID); + JsonNode pkRangeIdNode = + rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID); if (pkRangeIdNode != null && pkRangeIdNode.isTextual()) { return new FeedRangePartitionKeyRangeImpl(pkRangeIdNode.asText()); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index 9fa6a6b4976a4..77ee40fb9b72c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -9,12 +9,10 @@ import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.Range; -import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; import java.util.ArrayList; -import java.util.Collections; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -70,7 +68,7 @@ public Mono>> getEffectiveRangesAsync( this.partitionKey, partitionKeyDefinition); Range range = Range.getPointRange(effectivePartitionKey); - ArrayList> rangeList = new ArrayList>(); + ArrayList> rangeList = new ArrayList<>(); rangeList.add(range); return Mono.just((UnmodifiableList>)UnmodifiableList.unmodifiableList(rangeList)); @@ -93,7 +91,7 @@ public Mono> getPartitionKeyRangesAsync( false, null) .flatMap(pkRangeHolder -> { - ArrayList rangeList = new ArrayList(); + ArrayList rangeList = new ArrayList<>(); if (pkRangeHolder != null) { String rangeId = pkRangeHolder.v.get(0).getId(); @@ -104,9 +102,12 @@ public Mono> getPartitionKeyRangesAsync( }); } - @Override - public String toJsonString() { - return this.partitionKey.toJson(); + public void populatePropertyBag() { + super.populatePropertyBag(); + + if (this.partitionKey != null) { + setProperty(this, Constants.Properties.FEED_RANGE_PARTITION_KEY, this.partitionKey); + } } @Override @@ -114,12 +115,9 @@ public String toString() { return this.partitionKey.toJson(); } - public void populatePropertyBag() { - super.populatePropertyBag(); - - if (this.partitionKey != null) { - setProperty(this, Constants.Properties.FEED_RANGE_PARTITION_KEY, this.partitionKey); - } + @Override + public String toJsonString() { + return this.partitionKey.toJson(); } private static Mono tryGetRangeByEffectivePartitionKey( diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java index e91248aa85345..75ea7605c5646 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java @@ -76,13 +76,12 @@ public Mono>> visitAsync(FeedRangeEpkImpl feedRange) { .flatMap(collectionResponse -> { final DocumentCollection collection = collectionResponse.getResource(); return partitionKeyRangeCache.tryGetOverlappingRangesAsync( - BridgeInternal.getMetaDataDiagnosticContext(null), collection.getResourceId(), + BridgeInternal.getMetaDataDiagnosticContext(null), + collection.getResourceId(), feedRange.getRange(), false, null); }); - return valueHolderMono.map(partitionKeyRangeListResponse -> { - return toFeedRanges(partitionKeyRangeListResponse); - }); + return valueHolderMono.map(FeedRangePartitionKeyRangeExtractorImpl::toFeedRanges); } private static UnmodifiableList> toFeedRanges( @@ -92,14 +91,9 @@ private static UnmodifiableList> toFeedRanges( throw new IllegalStateException("PartitionKeyRange list cannot be null"); } - final List> feedRanges = new ArrayList>(); - partitionKeyRangeList.forEach(pkRange -> { - feedRanges.add(pkRange.toRange()); - }); - - final UnmodifiableList> feedRangesResult = - (UnmodifiableList>)UnmodifiableList.unmodifiableList(feedRanges); + final List> feedRanges = new ArrayList<>(); + partitionKeyRangeList.forEach(pkRange -> feedRanges.add(pkRange.toRange())); - return feedRangesResult; + return (UnmodifiableList>)UnmodifiableList.unmodifiableList(feedRanges); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index dbdc7f9d3d555..1b9418dd12a7f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -4,7 +4,6 @@ package com.azure.cosmos.implementation.feedranges; import com.azure.cosmos.implementation.Constants; -import com.azure.cosmos.implementation.GoneException; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; @@ -16,7 +15,6 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; -import java.util.Collections; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -98,7 +96,8 @@ public Mono>> getEffectiveRangesAsync( return Mono.error( new PartitionKeyRangeGoneException( String.format( - "The PartitionKeyRangeId: \"%s\" is not valid for the current container %s .", + "The PartitionKeyRangeId: \"%s\" is not valid for the current " + + "container %s .", partitionKeyRangeId, containerRid) )); @@ -108,7 +107,7 @@ public Mono>> getEffectiveRangesAsync( }); return getPkRangeTask.flatMap((pkRangeHolder) -> { - final ArrayList> temp = new ArrayList>(); + final ArrayList> temp = new ArrayList<>(); if (pkRangeHolder != null) { temp.add(pkRangeHolder.v.toRange()); } @@ -123,20 +122,11 @@ public Mono> getPartitionKeyRangesAsync( final String containerRid, final PartitionKeyDefinition partitionKeyDefinition) { - final ArrayList temp = new ArrayList(); + final ArrayList temp = new ArrayList<>(); temp.add(this.partitionKeyRangeId); - return Mono.just((UnmodifiableList)UnmodifiableList.unmodifiableList(temp)); - } - - @Override - public String toJsonString() { - return this.partitionKeyRangeId; - } - - @Override - public String toString() { - return this.partitionKeyRangeId; + return Mono.just( + (UnmodifiableList)UnmodifiableList.unmodifiableList(temp)); } public void populatePropertyBag() { @@ -149,4 +139,14 @@ public void populatePropertyBag() { this.partitionKeyRangeId); } } + + @Override + public String toString() { + return this.partitionKeyRangeId; + } + + @Override + public String toJsonString() { + return this.partitionKeyRangeId; + } } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java index dee731f2ea236..c6b16bab413d4 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.java @@ -17,8 +17,7 @@ final class FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl public final static FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl SINGLETON = new FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl(); - private FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl() - { + private FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl() { } @Override @@ -42,7 +41,8 @@ public void visit(FeedRangeEpkImpl feedRange, } @Override - public void visit(FeedRangePartitionKeyRangeImpl feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { + public void visit(FeedRangePartitionKeyRangeImpl feedRange, + RxDocumentServiceRequest rxDocumentServiceRequest) { checkNotNull(feedRange, "'feedRange' must not be null"); checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); @@ -51,7 +51,8 @@ public void visit(FeedRangePartitionKeyRangeImpl feedRange, RxDocumentServiceReq } @Override - public void visit(FeedRangePartitionKeyImpl feedRange, RxDocumentServiceRequest rxDocumentServiceRequest) { + public void visit(FeedRangePartitionKeyImpl feedRange, + RxDocumentServiceRequest rxDocumentServiceRequest) { checkNotNull(feedRange, "'feedRange' must not be null"); checkNotNull(rxDocumentServiceRequest, "'rxDocumentServiceRequest' must not be null"); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java index 78e41e964b9b0..0b9cee7953858 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/FeedRange.java @@ -8,7 +8,7 @@ import java.io.IOException; -@Beta(Beta.SinceVersion.NextMinorRelease) +@Beta(Beta.SinceVersion.V4_9_0) public interface FeedRange { /** * Creates a range from a previously obtained string representation. diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java index 078bf9a3d7cd8..ac92720730665 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/util/Beta.java @@ -50,7 +50,5 @@ public enum SinceVersion { V4_8_0, /** v4.9.0 */ V4_9_0, - /** NextMinorRelease */ - NextMinorRelease, } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 6b15dc686f5cf..345e98973bfe5 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -394,11 +394,11 @@ public void feedRangeEPK_RequestVisitor() { RxDocumentServiceRequest request = createMockRequest(true); feedRange.accept( FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); - assertThat(request.getProperties()).hasSize(2); - assertThat(request.getProperties().get(EpkRequestPropertyConstants.START_EPK_STRING)) + assertThat(request.getPropertiesOrThrow()).hasSize(2); + assertThat(request.getPropertiesOrThrow().get(EpkRequestPropertyConstants.START_EPK_STRING)) .isNotNull() .isEqualTo("AA"); - assertThat(request.getProperties().get(EpkRequestPropertyConstants.END_EPK_STRING)) + assertThat(request.getPropertiesOrThrow().get(EpkRequestPropertyConstants.END_EPK_STRING)) .isNotNull() .isEqualTo("BB"); } From 4811e5034bea83f2555f13ab6fb51f9c7defbd68 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 14:50:19 +0000 Subject: [PATCH 13/17] Prettifying feed range tests --- .../feedranges/FeedRangeTest.java | 417 +++++++++--------- 1 file changed, 209 insertions(+), 208 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 345e98973bfe5..63e34bb79d0d2 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -32,9 +32,9 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Mockito.when; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; public class FeedRangeTest { @@ -46,24 +46,33 @@ public void feedRangeEPK_Range() { } @Test(groups = "unit") - public void feedRangePK_PK() - { - PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); - FeedRangePartitionKeyImpl feedRangePartitionKey = new FeedRangePartitionKeyImpl(partitionKey); - assertThat(partitionKey).isEqualTo(feedRangePartitionKey.getPartitionKeyInternal()); + public void feedRangeEPK_RequestVisitor() { + Range range = new Range<>("AA", "BB", true, false); + FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); + RxDocumentServiceRequest request = createMockRequest(true); + feedRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + assertThat(request.getPropertiesOrThrow()).hasSize(2); + assertThat(request.getPropertiesOrThrow().get(EpkRequestPropertyConstants.START_EPK_STRING)) + .isNotNull() + .isEqualTo("AA"); + assertThat(request.getPropertiesOrThrow().get(EpkRequestPropertyConstants.END_EPK_STRING)) + .isNotNull() + .isEqualTo("BB"); } @Test(groups = "unit") - public void feedRangePKRangeId_PKRange() - { - String pkRangeId = UUID.randomUUID().toString(); - FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = new FeedRangePartitionKeyRangeImpl(pkRangeId); - assertThat(pkRangeId).isEqualTo(feedRangePartitionKeyRange.getPartitionKeyRangeId()); + public void feedRangeEPK_RequestVisitor_ThrowsWhenNoPropertiesAvailable() { + Range range = new Range<>("AA", "BB", true, false); + FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); + RxDocumentServiceRequest request = createMockRequest(false); + assertThat(catchThrowableOfType(() -> feedRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request), + IllegalStateException.class)).isNotNull(); } @Test(groups = "unit") - public void feedRangeEPK_getEffectiveRangesAsync() - { + public void feedRangeEPK_getEffectiveRangesAsync() { Range range = new Range<>("AA", "BB", true, false); FeedRangeEpkImpl FeedRangeEpk = new FeedRangeEpkImpl(range); @@ -86,36 +95,103 @@ public void feedRangeEPK_getEffectiveRangesAsync() } @Test(groups = "unit") - public void feedRangePK_getEffectiveRangesAsync() - { - PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); - partitionKeyDefinition.getPaths().add("/id"); - PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); - FeedRangePartitionKeyImpl feedRangePartitionKey = new FeedRangePartitionKeyImpl(partitionKey); - Range range = Range.getPointRange( - partitionKey.getEffectivePartitionKeyString(partitionKey, partitionKeyDefinition)); + public void feedRangeEPK_getPartitionKeyRangesAsync() { + Range range = new Range<>("AA", "BB", true, false); + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive(range.getMin()) + .setMaxExclusive(range.getMax()); + List pkRanges = new ArrayList<>(); + pkRanges.add(partitionKeyRange); IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetOverlappingRangesAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(range), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); + + FeedRangeEpkImpl feedRangeEpk = new FeedRangeEpkImpl(range); StepVerifier .create( - feedRangePartitionKey.getEffectiveRangesAsync( + feedRangeEpk.getPartitionKeyRangesAsync( routingMapProviderMock, null, - partitionKeyDefinition)) + null)) .recordWith(ArrayList::new) .expectNextCount(1) .consumeRecordedWith(r -> { assertThat(r).hasSize(1); - assertThat(new ArrayList<>(r).get(0)) + UnmodifiableList response = new ArrayList<>(r).get(0); + assertThat(response) .hasSize(1) - .contains(range); + .contains(partitionKeyRange.getId()); }) .verifyComplete(); + + Mockito + .verify(routingMapProviderMock, Mockito.times(1)) + .tryGetOverlappingRangesAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(range), + eq(false), + anyMapOf(String.class, Object.class)); + } + + @Test(groups = "unit") + public void feedRangeEPK_toJsonFromJson() { + Range range = new Range<>("AA", "BB", true, false); + FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); + String representation = feedRange.toJson(); + assertThat(FeedRange.fromJsonString(representation)) + .isNotNull() + .isInstanceOf(FeedRangeEpkImpl.class); + FeedRangeEpkImpl feedRangeDeserialized = + (FeedRangeEpkImpl)FeedRange.fromJsonString(representation); + String representationAfterDeserialization = feedRangeDeserialized.toJson(); + assertThat(representationAfterDeserialization).isEqualTo(representation); + assertThat(feedRangeDeserialized.getRange()).isNotNull(); + assertThat(feedRangeDeserialized.getRange().getMin()) + .isNotNull() + .isEqualTo(range.getMin()); + assertThat(feedRangeDeserialized.getRange().getMax()) + .isNotNull() + .isEqualTo(range.getMax()); + } + + @Test(groups = "unit") + public void feedRangePKRangeId_PKRange() { + String pkRangeId = UUID.randomUUID().toString(); + FeedRangePartitionKeyRangeImpl feedRangePartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(pkRangeId); + assertThat(pkRangeId).isEqualTo(feedRangePartitionKeyRange.getPartitionKeyRangeId()); } @Test(groups = "unit") - public void feedRangePKRangeId_getEffectiveRangesAsync() - { + public void feedRangePKRangeId_RequestVisitor() { + Range range = new Range<>("AA", "BB", true, false); + String pkRangeId = UUID.randomUUID().toString(); + PartitionKeyRange partitionKeyRange = new PartitionKeyRange() + .setId(pkRangeId) + .setMinInclusive(range.getMin()) + .setMaxExclusive(range.getMax()); + + FeedRangePartitionKeyRangeImpl feedRangPartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + + RxDocumentServiceRequest request = createMockRequest(true); + feedRangPartitionKeyRange.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + assertThat(request.getPartitionKeyRangeIdentity()).isNotNull(); + } + + @Test(groups = "unit") + public void feedRangePKRangeId_getEffectiveRangesAsync() { String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() .setId(pkRangeId) @@ -164,8 +240,7 @@ public void feedRangePKRangeId_getEffectiveRangesAsync() } @Test(groups = "unit") - public void feedRangePKRangeId_getEffectiveRangesAsync_Refresh() - { + public void feedRangePKRangeId_getEffectiveRangesAsync_Null() { String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() .setId(pkRangeId) @@ -183,40 +258,24 @@ public void feedRangePKRangeId_getEffectiveRangesAsync_Refresh() anyBoolean(), anyMapOf(String.class, Object.class))) .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))) - .thenReturn(Mono.just(Utils.ValueHolder.initialize(partitionKeyRange))); + .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))); StepVerifier .create( feedRangePartitionKeyRange.getEffectiveRangesAsync( routingMapProviderMock, null, null)) .recordWith(ArrayList::new) - .expectNextCount(1) - .consumeRecordedWith(r -> { - assertThat(r).hasSize(1); - UnmodifiableList> ranges = new ArrayList<>(r).get(0); - assertThat(ranges).hasSize(1); - Range range = ranges.get(0); - assertThat(range).isNotNull(); - assertThat(range.getMin()).isEqualTo(partitionKeyRange.getMinInclusive()); - assertThat(range.getMax()).isEqualTo(partitionKeyRange.getMaxExclusive()); - assertThat(range.getMin()).isEqualTo(partitionKeyRange.toRange().getMin()); - assertThat(range.getMax()).isEqualTo(partitionKeyRange.toRange().getMax()); + .expectErrorSatisfies((e) -> { + assertThat(e).isInstanceOf(PartitionKeyRangeGoneException.class); + PartitionKeyRangeGoneException pkGoneException = (PartitionKeyRangeGoneException)e; + assertThat(pkGoneException.getSubStatusCode()) + .isEqualTo(HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE); }) - .verifyComplete(); - - Mockito - .verify(routingMapProviderMock, Mockito.times(2)) - .tryGetPartitionKeyRangeByIdAsync( - any(MetadataDiagnosticsContext.class), - anyString(), - eq(partitionKeyRange.getId()), - anyBoolean(), - anyMapOf(String.class, Object.class)); + .verify(); } @Test(groups = "unit") - public void feedRangePKRangeId_getEffectiveRangesAsync_Null() - { + public void feedRangePKRangeId_getEffectiveRangesAsync_Refresh() { String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() .setId(pkRangeId) @@ -234,25 +293,39 @@ public void feedRangePKRangeId_getEffectiveRangesAsync_Null() anyBoolean(), anyMapOf(String.class, Object.class))) .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))) - .thenReturn(Mono.just(Utils.ValueHolder.initialize(null))); + .thenReturn(Mono.just(Utils.ValueHolder.initialize(partitionKeyRange))); StepVerifier .create( feedRangePartitionKeyRange.getEffectiveRangesAsync( routingMapProviderMock, null, null)) .recordWith(ArrayList::new) - .expectErrorSatisfies((e) -> { - assertThat(e).isInstanceOf(PartitionKeyRangeGoneException.class); - PartitionKeyRangeGoneException pkGoneException = (PartitionKeyRangeGoneException)e; - assertThat(pkGoneException.getSubStatusCode()) - .isEqualTo(HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE); + .expectNextCount(1) + .consumeRecordedWith(r -> { + assertThat(r).hasSize(1); + UnmodifiableList> ranges = new ArrayList<>(r).get(0); + assertThat(ranges).hasSize(1); + Range range = ranges.get(0); + assertThat(range).isNotNull(); + assertThat(range.getMin()).isEqualTo(partitionKeyRange.getMinInclusive()); + assertThat(range.getMax()).isEqualTo(partitionKeyRange.getMaxExclusive()); + assertThat(range.getMin()).isEqualTo(partitionKeyRange.toRange().getMin()); + assertThat(range.getMax()).isEqualTo(partitionKeyRange.toRange().getMax()); }) - .verify(); + .verifyComplete(); + + Mockito + .verify(routingMapProviderMock, Mockito.times(2)) + .tryGetPartitionKeyRangeByIdAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + eq(partitionKeyRange.getId()), + anyBoolean(), + anyMapOf(String.class, Object.class)); } @Test(groups = "unit") - public void feedRangeEPK_getPartitionKeyRangesAsync() - { + public void feedRangePKRangeId_getPartitionKeyRangesAsync() { Range range = new Range<>("AA", "BB", true, false); String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() @@ -260,22 +333,13 @@ public void feedRangeEPK_getPartitionKeyRangesAsync() .setMinInclusive(range.getMin()) .setMaxExclusive(range.getMax()); - List pkRanges = new ArrayList<>(); - pkRanges.add(partitionKeyRange); - IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); - when( - routingMapProviderMock.tryGetOverlappingRangesAsync( - any(MetadataDiagnosticsContext.class), - anyString(), - eq(range), - anyBoolean(), - anyMapOf(String.class, Object.class))) - .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); + FeedRangePartitionKeyRangeImpl feedRangPartitionKeyRange = + new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); - FeedRangeEpkImpl feedRangeEpk = new FeedRangeEpkImpl(range); + IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); StepVerifier .create( - feedRangeEpk.getPartitionKeyRangesAsync( + feedRangPartitionKeyRange.getPartitionKeyRangesAsync( routingMapProviderMock, null, null)) @@ -289,47 +353,61 @@ public void feedRangeEPK_getPartitionKeyRangesAsync() .contains(partitionKeyRange.getId()); }) .verifyComplete(); + } - Mockito - .verify(routingMapProviderMock, Mockito.times(1)) - .tryGetOverlappingRangesAsync( - any(MetadataDiagnosticsContext.class), - anyString(), - eq(range), - eq(false), - anyMapOf(String.class, Object.class)); + @Test(groups = "unit") + public void feedRangePKRangeId_toJsonFromJson() { + String pkRangeId = UUID.randomUUID().toString(); + FeedRangePartitionKeyRangeImpl feedRange = new FeedRangePartitionKeyRangeImpl(pkRangeId); + String representation = feedRange.toJson(); + assertThat(FeedRange.fromJsonString(representation)) + .isNotNull() + .isInstanceOf(FeedRangePartitionKeyRangeImpl.class); + FeedRangePartitionKeyRangeImpl feedRangeDeserialized = + (FeedRangePartitionKeyRangeImpl)FeedRange.fromJsonString(representation); + String representationAfterDeserialization = feedRangeDeserialized.toJson(); + assertThat(representationAfterDeserialization).isEqualTo(representation); + } + + @Test(groups = "unit") + public void feedRangePK_PK() { + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal( + "Test"); + FeedRangePartitionKeyImpl feedRangePartitionKey = + new FeedRangePartitionKeyImpl(partitionKey); + assertThat(partitionKey).isEqualTo(feedRangePartitionKey.getPartitionKeyInternal()); + } + + @Test(groups = "unit") + public void feedRangePK_RequestVisitor() { + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal( + "Test"); + FeedRangePartitionKeyImpl feedRangePartitionKey = + new FeedRangePartitionKeyImpl(partitionKey); + RxDocumentServiceRequest request = createMockRequest(true); + feedRangePartitionKey.accept( + FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); + assertThat(request.getPartitionKeyInternal()).isNotNull(); + assertThat(request.getPartitionKeyInternal().toJson()) + .isNotNull() + .isEqualTo(request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY)); } @Test(groups = "unit") - public void feedRangePK_getPartitionKeyRangesAsync() - { + public void feedRangePK_getEffectiveRangesAsync() { PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); partitionKeyDefinition.getPaths().add("/id"); - PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); - - Range range = new Range<>("AA", "BB", true, false); - String pkRangeId = UUID.randomUUID().toString(); - PartitionKeyRange partitionKeyRange = new PartitionKeyRange() - .setId(pkRangeId) - .setMinInclusive(range.getMin()) - .setMaxExclusive(range.getMax()); - List pkRanges = new ArrayList<>(); - pkRanges.add(partitionKeyRange); + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal( + "Test"); + FeedRangePartitionKeyImpl feedRangePartitionKey = + new FeedRangePartitionKeyImpl(partitionKey); + Range range = Range.getPointRange( + partitionKey.getEffectivePartitionKeyString(partitionKey, partitionKeyDefinition)); IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); - when( - routingMapProviderMock.tryGetOverlappingRangesAsync( - any(MetadataDiagnosticsContext.class), - anyString(), - any(), - anyBoolean(), - anyMapOf(String.class, Object.class))) - .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); - - FeedRangePartitionKeyImpl feedRangPartitionKey = new FeedRangePartitionKeyImpl(partitionKey); StepVerifier .create( - feedRangPartitionKey.getPartitionKeyRangesAsync( + feedRangePartitionKey.getEffectiveRangesAsync( routingMapProviderMock, null, partitionKeyDefinition)) @@ -337,34 +415,47 @@ public void feedRangePK_getPartitionKeyRangesAsync() .expectNextCount(1) .consumeRecordedWith(r -> { assertThat(r).hasSize(1); - UnmodifiableList response = new ArrayList<>(r).get(0); - assertThat(response) + assertThat(new ArrayList<>(r).get(0)) .hasSize(1) - .contains(partitionKeyRange.getId()); + .contains(range); }) .verifyComplete(); } @Test(groups = "unit") - public void feedRangePKRangeId_getPartitionKeyRangesAsync() - { + public void feedRangePK_getPartitionKeyRangesAsync() { + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.getPaths().add("/id"); + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal( + "Test"); + Range range = new Range<>("AA", "BB", true, false); String pkRangeId = UUID.randomUUID().toString(); PartitionKeyRange partitionKeyRange = new PartitionKeyRange() .setId(pkRangeId) .setMinInclusive(range.getMin()) .setMaxExclusive(range.getMax()); - - FeedRangePartitionKeyRangeImpl feedRangPartitionKeyRange = - new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); + List pkRanges = new ArrayList<>(); + pkRanges.add(partitionKeyRange); IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); + when( + routingMapProviderMock.tryGetOverlappingRangesAsync( + any(MetadataDiagnosticsContext.class), + anyString(), + any(), + anyBoolean(), + anyMapOf(String.class, Object.class))) + .thenReturn(Mono.just(Utils.ValueHolder.initialize(pkRanges))); + + FeedRangePartitionKeyImpl feedRangPartitionKey = + new FeedRangePartitionKeyImpl(partitionKey); StepVerifier .create( - feedRangPartitionKeyRange.getPartitionKeyRangesAsync( + feedRangPartitionKey.getPartitionKeyRangesAsync( routingMapProviderMock, null, - null)) + partitionKeyDefinition)) .recordWith(ArrayList::new) .expectNextCount(1) .consumeRecordedWith(r -> { @@ -377,86 +468,10 @@ public void feedRangePKRangeId_getPartitionKeyRangesAsync() .verifyComplete(); } - @Test(groups = "unit") - public void feedRangeEPK_RequestVisitor_ThrowsWhenNoPropertiesAvailable() { - Range range = new Range<>("AA", "BB", true, false); - FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); - RxDocumentServiceRequest request = createMockRequest(false); - assertThat(catchThrowableOfType(() -> feedRange.accept( - FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request), - IllegalStateException.class)).isNotNull(); - } - - @Test(groups = "unit") - public void feedRangeEPK_RequestVisitor() { - Range range = new Range<>("AA", "BB", true, false); - FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); - RxDocumentServiceRequest request = createMockRequest(true); - feedRange.accept( - FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); - assertThat(request.getPropertiesOrThrow()).hasSize(2); - assertThat(request.getPropertiesOrThrow().get(EpkRequestPropertyConstants.START_EPK_STRING)) - .isNotNull() - .isEqualTo("AA"); - assertThat(request.getPropertiesOrThrow().get(EpkRequestPropertyConstants.END_EPK_STRING)) - .isNotNull() - .isEqualTo("BB"); - } - - @Test(groups = "unit") - public void feedRangePKRangeId_RequestVisitor() { - Range range = new Range<>("AA", "BB", true, false); - String pkRangeId = UUID.randomUUID().toString(); - PartitionKeyRange partitionKeyRange = new PartitionKeyRange() - .setId(pkRangeId) - .setMinInclusive(range.getMin()) - .setMaxExclusive(range.getMax()); - - FeedRangePartitionKeyRangeImpl feedRangPartitionKeyRange = - new FeedRangePartitionKeyRangeImpl(partitionKeyRange.getId()); - - RxDocumentServiceRequest request = createMockRequest(true); - feedRangPartitionKeyRange.accept( - FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); - assertThat(request.getPartitionKeyRangeIdentity()).isNotNull(); - } - - @Test(groups = "unit") - public void feedRangePK_RequestVisitor() { - PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); - FeedRangePartitionKeyImpl feedRangePartitionKey = new FeedRangePartitionKeyImpl(partitionKey); - RxDocumentServiceRequest request = createMockRequest(true); - feedRangePartitionKey.accept( - FeedRangeRxDocumentServiceRequestPopulatorVisitorImpl.SINGLETON, request); - assertThat(request.getPartitionKeyInternal()).isNotNull(); - assertThat(request.getPartitionKeyInternal().toJson()) - .isNotNull() - .isEqualTo(request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY)); - } - - @Test(groups = "unit") - public void feedRangeEPK_toJsonFromJson() { - Range range = new Range<>("AA", "BB", true, false); - FeedRangeEpkImpl feedRange = new FeedRangeEpkImpl(range); - String representation = feedRange.toJson(); - assertThat(FeedRange.fromJsonString(representation)) - .isNotNull() - .isInstanceOf(FeedRangeEpkImpl.class); - FeedRangeEpkImpl feedRangeDeserialized = (FeedRangeEpkImpl)FeedRange.fromJsonString(representation); - String representationAfterDeserialization = feedRangeDeserialized.toJson(); - assertThat(representationAfterDeserialization).isEqualTo(representation); - assertThat(feedRangeDeserialized.getRange()).isNotNull(); - assertThat(feedRangeDeserialized.getRange().getMin()) - .isNotNull() - .isEqualTo(range.getMin()); - assertThat(feedRangeDeserialized.getRange().getMax()) - .isNotNull() - .isEqualTo(range.getMax()); - } - @Test(groups = "unit") public void feedRangePK_toJsonFromJson() { - PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal("Test"); + PartitionKeyInternal partitionKey = PartitionKeyInternalUtils.createPartitionKeyInternal( + "Test"); FeedRangePartitionKeyImpl feedRange = new FeedRangePartitionKeyImpl(partitionKey); String representation = feedRange.toJson(); assertThat(FeedRange.fromJsonString(representation)) @@ -468,20 +483,6 @@ public void feedRangePK_toJsonFromJson() { assertThat(representationAfterDeserialization).isEqualTo(representation); } - @Test(groups = "unit") - public void feedRangePKRangeId_toJsonFromJson() { - String pkRangeId = UUID.randomUUID().toString(); - FeedRangePartitionKeyRangeImpl feedRange = new FeedRangePartitionKeyRangeImpl(pkRangeId); - String representation = feedRange.toJson(); - assertThat(FeedRange.fromJsonString(representation)) - .isNotNull() - .isInstanceOf(FeedRangePartitionKeyRangeImpl.class); - FeedRangePartitionKeyRangeImpl feedRangeDeserialized = - (FeedRangePartitionKeyRangeImpl)FeedRange.fromJsonString(representation); - String representationAfterDeserialization = feedRangeDeserialized.toJson(); - assertThat(representationAfterDeserialization).isEqualTo(representation); - } - private static RxDocumentServiceRequest createMockRequest(boolean hasProperties) { RequestOptions requestOptions = new RequestOptions(); From 6515ff53e639ae4b2f6c9e1afab9a1cd7ce84f1d Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 15:14:38 +0000 Subject: [PATCH 14/17] Fixes and new test for Conatiner.getFeedRanges() --- .../implementation/RxDocumentClientImpl.java | 5 +---- .../feedranges/FeedRangeEpkImpl.java | 12 ----------- .../feedranges/FeedRangePartitionKeyImpl.java | 7 ++----- .../FeedRangePartitionKeyRangeImpl.java | 7 ++----- .../com/azure/cosmos/CosmosContainerTest.java | 21 +++++++++++++++++++ 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java index d1a3f3013839f..d3aa5f84f68be 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java @@ -3687,10 +3687,7 @@ private static List toFeedRanges( feedRanges.add(toFeedRange(pkRange)); }); - UnmodifiableList feedRangesResult = (UnmodifiableList) Collections - .unmodifiableList(feedRanges); - - return feedRangesResult; + return feedRanges; } private static FeedRange toFeedRange(PartitionKeyRange pkRange) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index 2885954918918..0a4f0497cf792 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -110,18 +110,6 @@ public Mono> getPartitionKeyRangesAsync( }); } - @Override - public String toJsonString() { - try { - return Utils.getSimpleObjectMapper().writeValueAsString(this); - } catch (final IOException e) { - throw new IllegalArgumentException( - "Unable serialize the feed range token for an extended partition key into a JSON " + - "string", - e); - } - } - @Override public String toString() { return this.range.toString(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index 77ee40fb9b72c..ea62ab04f5492 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -6,12 +6,14 @@ import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; +import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; +import java.io.IOException; import java.util.ArrayList; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -115,11 +117,6 @@ public String toString() { return this.partitionKey.toJson(); } - @Override - public String toJsonString() { - return this.partitionKey.toJson(); - } - private static Mono tryGetRangeByEffectivePartitionKey( IRoutingMapProvider routingMapProvider, String containerRid, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index 1b9418dd12a7f..b133dd3c207e6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -7,6 +7,7 @@ import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; +import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.Utils.ValueHolder; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; @@ -14,6 +15,7 @@ import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; +import java.io.IOException; import java.util.ArrayList; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -144,9 +146,4 @@ public void populatePropertyBag() { public String toString() { return this.partitionKeyRangeId; } - - @Override - public String toJsonString() { - return this.partitionKeyRangeId; - } } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java index 39c7f7f9d1292..272614e48a531 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosContainerTest.java @@ -11,6 +11,7 @@ import com.azure.cosmos.models.CosmosContainerRequestOptions; import com.azure.cosmos.models.CosmosContainerResponse; import com.azure.cosmos.models.CosmosQueryRequestOptions; +import com.azure.cosmos.models.FeedRange; import com.azure.cosmos.models.IndexingMode; import com.azure.cosmos.models.IndexingPolicy; import com.azure.cosmos.models.SqlQuerySpec; @@ -23,6 +24,7 @@ import org.testng.annotations.Factory; import org.testng.annotations.Test; +import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -176,6 +178,25 @@ public void readContainer() throws Exception { validateContainerResponse(containerProperties, read1); } + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void getFeedRanges() throws Exception { + String collectionName = UUID.randomUUID().toString(); + CosmosContainerProperties containerProperties = getCollectionDefinition(collectionName); + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + + CosmosContainerResponse containerResponse = createdDatabase.createContainer(containerProperties); + + CosmosContainer syncContainer = createdDatabase.getContainer(collectionName); + + List feedRanges = syncContainer.getFeedRanges(); + assertThat(feedRanges) + .isNotNull() + .hasSize(1); + assertThat(feedRanges.get(0).toJsonString()) + .isNotNull() + .isEqualTo("{\"PKRangeId\":\"0\"}"); + } + @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void deleteContainer() throws Exception { String collectionName = UUID.randomUUID().toString(); From 30e162e89883176c3bee6988e0e40e8b1ea0fbcd Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Fri, 13 Nov 2020 17:31:29 +0000 Subject: [PATCH 15/17] Addressing some SpotBug violations --- .../feedranges/FeedRangeContinuation.java | 5 +++-- .../feedranges/FeedRangeEpkImpl.java | 18 ++++++++++++++--- .../feedranges/FeedRangePartitionKeyImpl.java | 20 +++++++++++++++---- .../FeedRangePartitionKeyRangeImpl.java | 16 +++++++++++++-- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java index c8fdc3ff0a60d..c5c9f3e33d2b3 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java @@ -10,7 +10,7 @@ import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; -abstract class FeedRangeContinuation { +public abstract class FeedRangeContinuation { protected final FeedRangeInternal feedRange; private final String containerRid; @@ -42,9 +42,10 @@ public FeedRangeInternal getFeedRange() { public abstract void validateContainer(String containerRid); + /* TODO fabianm - infinite recursion public static FeedRangeContinuation tryParse(String toStringValue) { return FeedRangeCompositeContinuationImpl.tryParse(toStringValue); - } + }*/ public abstract ShouldRetryResult handleChangeFeedNotModified( RxDocumentServiceResponse responseMessage); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index 0a4f0497cf792..7def36144804d 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -6,7 +6,6 @@ import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; -import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternalHelper; import com.azure.cosmos.implementation.routing.Range; @@ -14,9 +13,9 @@ import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; -import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -43,7 +42,7 @@ public Range getRange() { return this.range; } - public static FeedRangeEpkImpl ForFullRange() { + public static FeedRangeEpkImpl forFullRange() { return fullRangeEPK; } @@ -115,6 +114,19 @@ public String toString() { return this.range.toString(); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FeedRangeEpkImpl that = (FeedRangeEpkImpl) o; + return Objects.equals(this.range, that.range); + } + + @Override + public int hashCode() { + return Objects.hash(range); + } + public void populatePropertyBag() { super.populatePropertyBag(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index ea62ab04f5492..64ae40b68ef01 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -5,16 +5,14 @@ import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.IRoutingMapProvider; -import com.azure.cosmos.implementation.PartitionKeyRange; -import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.Range; import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; -import java.io.IOException; import java.util.ArrayList; +import java.util.Objects; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -117,6 +115,20 @@ public String toString() { return this.partitionKey.toJson(); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FeedRangePartitionKeyImpl that = (FeedRangePartitionKeyImpl) o; + return Objects.equals(this.partitionKey, that.partitionKey); + } + + @Override + public int hashCode() { + return Objects.hash(partitionKey); + } + + /* TODO fabianm - not needed yet private static Mono tryGetRangeByEffectivePartitionKey( IRoutingMapProvider routingMapProvider, String containerRid, @@ -136,5 +148,5 @@ private static Mono tryGetRangeByEffectivePartitionKey( return Mono.just(pkRangeHolder.v.get(0)); }); - } + }*/ } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index b133dd3c207e6..7a1ee0f460f8e 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -7,7 +7,6 @@ import com.azure.cosmos.implementation.IRoutingMapProvider; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; -import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.Utils.ValueHolder; import com.azure.cosmos.implementation.apachecommons.collections.list.UnmodifiableList; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; @@ -15,8 +14,8 @@ import com.azure.cosmos.models.PartitionKeyDefinition; import reactor.core.publisher.Mono; -import java.io.IOException; import java.util.ArrayList; +import java.util.Objects; import static com.azure.cosmos.BridgeInternal.setProperty; @@ -146,4 +145,17 @@ public void populatePropertyBag() { public String toString() { return this.partitionKeyRangeId; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FeedRangePartitionKeyRangeImpl that = (FeedRangePartitionKeyRangeImpl) o; + return Objects.equals(this.partitionKeyRangeId, that.partitionKeyRangeId); + } + + @Override + public int hashCode() { + return Objects.hash(partitionKeyRangeId); + } } \ No newline at end of file From 8ac208ae1698576552b9455cf224391866055d91 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Tue, 17 Nov 2020 23:38:04 +0000 Subject: [PATCH 16/17] Reacting to code review feedback --- .../implementation/RxDocumentClientImpl.java | 2 +- .../implementation/ShouldRetryResult.java | 2 + .../feedranges/FeedRangeAsyncVisitor.java | 6 +- .../FeedRangeAsyncVisitorWithArg.java | 8 +- .../FeedRangeCompositeContinuationImpl.java | 41 ++++------ .../feedranges/FeedRangeContinuation.java | 2 +- .../feedranges/FeedRangeEpkImpl.java | 29 +++---- .../feedranges/FeedRangeInternal.java | 77 +++++++++---------- .../feedranges/FeedRangePartitionKeyImpl.java | 29 +++---- ...edRangePartitionKeyRangeExtractorImpl.java | 10 +-- .../FeedRangePartitionKeyRangeImpl.java | 29 +++---- .../feedranges/FeedRangeTest.java | 18 +++-- 12 files changed, 108 insertions(+), 145 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java index d3aa5f84f68be..fa68b4c1db91f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java @@ -3682,7 +3682,7 @@ private static List toFeedRanges( throw new IllegalStateException("PartitionKeyRange list cannot be null"); } - List feedRanges = new ArrayList(); + List feedRanges = new ArrayList(partitionKeyRangeList.size()); partitionKeyRangeList.forEach(pkRange -> { feedRanges.add(toFeedRange(pkRange)); }); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java index bf32924e9cded..2d5b7b188c830 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/ShouldRetryResult.java @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. package com.azure.cosmos.implementation; import java.time.Duration; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java index e2f8f4c1a5f64..9a6f2383a8f09 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitor.java @@ -6,9 +6,9 @@ import reactor.core.publisher.Mono; abstract class FeedRangeAsyncVisitor { - public abstract Mono visitAsync(FeedRangePartitionKeyImpl feedRange); + public abstract Mono visit(FeedRangePartitionKeyImpl feedRange); - public abstract Mono visitAsync(FeedRangePartitionKeyRangeImpl feedRange); + public abstract Mono visit(FeedRangePartitionKeyRangeImpl feedRange); - public abstract Mono visitAsync(FeedRangeEpkImpl feedRange); + public abstract Mono visit(FeedRangeEpkImpl feedRange); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java index 67a239aa70f12..3590a22ee1a84 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeAsyncVisitorWithArg.java @@ -6,10 +6,10 @@ import reactor.core.publisher.Mono; abstract class FeedRangeAsyncVisitorWithArg { - public abstract Mono visitAsync(FeedRangePartitionKeyImpl feedRange, TArg argument); + public abstract Mono visit(FeedRangePartitionKeyImpl feedRange, TArg argument); - public abstract Mono visitAsync(FeedRangePartitionKeyRangeImpl feedRange, - TArg argument); + public abstract Mono visit(FeedRangePartitionKeyRangeImpl feedRange, + TArg argument); - public abstract Mono visitAsync(FeedRangeEpkImpl feedRange, TArg argument); + public abstract Mono visit(FeedRangeEpkImpl feedRange, TArg argument); } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java index 3f4ab2a963ed5..19e1237c2304f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeCompositeContinuationImpl.java @@ -12,9 +12,12 @@ import com.azure.cosmos.implementation.Strings; import com.azure.cosmos.implementation.Utils; import com.azure.cosmos.implementation.caches.RxPartitionKeyRangeCache; +import com.azure.cosmos.implementation.directconnectivity.GatewayAddressCache; import com.azure.cosmos.implementation.query.CompositeContinuationToken; import com.azure.cosmos.implementation.routing.Range; import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; import java.io.IOException; @@ -32,6 +35,7 @@ */ final class FeedRangeCompositeContinuationImpl extends FeedRangeContinuation { + private final static Logger LOGGER = LoggerFactory.getLogger(FeedRangeCompositeContinuationImpl.class); private final static ShouldRetryResult NO_RETRY = ShouldRetryResult.noRetry(); private final static ShouldRetryResult RETRY = ShouldRetryResult.retryAfter(Duration.ZERO); private final Queue compositeContinuationTokens; @@ -139,10 +143,7 @@ public void validateContainer(final String containerRid) throws IllegalArgumentE @Override public ShouldRetryResult handleChangeFeedNotModified(final RxDocumentServiceResponse response) { - if (response == null) { - throw new NullPointerException("response"); - } - + checkNotNull(response, "Argument 'response' must not be null"); final int statusCode = response.getStatusCode(); if (statusCode >= HttpConstants.StatusCodes.MINIMUM_SUCCESS_STATUSCODE && statusCode <= HttpConstants.StatusCodes.MAXIMUM_SUCCESS_STATUSCODE) { @@ -171,16 +172,11 @@ public ShouldRetryResult handleChangeFeedNotModified(final RxDocumentServiceResp } @Override - public Mono handleSplitAsync(final RxDocumentClientImpl client, - final RxDocumentServiceResponse response) { + public Mono handleSplit(final RxDocumentClientImpl client, + final RxDocumentServiceResponse response) { - if (client == null) { - throw new NullPointerException("client"); - } - - if (response == null) { - throw new NullPointerException("response"); - } + checkNotNull(client, "Argument 'client' must not be null"); + checkNotNull(response, "Argument 'response' must not be null"); Integer nSubStatus = 0; final String valueSubStatus = @@ -200,7 +196,7 @@ public Mono handleSplitAsync(final RxDocumentClientImpl clien final RxPartitionKeyRangeCache partitionKeyRangeCache = client.getPartitionKeyRangeCache(); final Mono>> resolvedRangesTask = - this.tryGetOverlappingRangesAsync( + this.tryGetOverlappingRanges( partitionKeyRangeCache, this.currentToken.getRange().getMin(), this.currentToken.getRange().getMax(), true); @@ -216,10 +212,7 @@ public Mono handleSplitAsync(final RxDocumentClientImpl clien @Override public void accept(final FeedRangeContinuationVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this); } @@ -248,12 +241,8 @@ public static FeedRangeCompositeContinuationImpl createFromDeserializedTokens( } public static FeedRangeContinuation parse(final String jsonString) throws IOException { - if (jsonString == null) { - throw new NullPointerException("jsonString"); - } - + checkNotNull(jsonString, "Argument 'jsonString' must not be null"); final ObjectMapper mapper = Utils.getSimpleObjectMapper(); - return mapper.readValue(jsonString, FeedRangeCompositeContinuationImpl.class); } @@ -330,7 +319,7 @@ private void moveToNextToken() { } } - private Mono>> tryGetOverlappingRangesAsync( + private Mono>> tryGetOverlappingRanges( final RxPartitionKeyRangeCache partitionKeyRangeCache, final String min, final String max, final Boolean forceRefresh) { @@ -360,6 +349,10 @@ private static CompositeContinuationToken tryParseAsCompositeContinuationToken( return null; } catch (final IOException ioError) { + LOGGER.debug( + "Failed to parse as composite continuation token JSON ", + providedContinuation, + ioError); return null; } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java index c5c9f3e33d2b3..c44fb43c82ddd 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeContinuation.java @@ -50,7 +50,7 @@ public static FeedRangeContinuation tryParse(String toStringValue) { public abstract ShouldRetryResult handleChangeFeedNotModified( RxDocumentServiceResponse responseMessage); - public abstract Mono handleSplitAsync( + public abstract Mono handleSplit( RxDocumentClientImpl client, RxDocumentServiceResponse responseMessage); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java index 7def36144804d..b14ea8f6fbb83 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeEpkImpl.java @@ -18,6 +18,7 @@ import java.util.Objects; import static com.azure.cosmos.BridgeInternal.setProperty; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; final class FeedRangeEpkImpl extends FeedRangeInternal { private static final FeedRangeEpkImpl fullRangeEPK = @@ -27,10 +28,7 @@ final class FeedRangeEpkImpl extends FeedRangeInternal { private final UnmodifiableList> rangeList; public FeedRangeEpkImpl(final Range range) { - if (range == null) { - throw new NullPointerException("range"); - } - + checkNotNull(range, "Argument 'range' must not be null"); this.range = range; final ArrayList> temp = new ArrayList<>(); temp.add(range); @@ -48,33 +46,24 @@ public static FeedRangeEpkImpl forFullRange() { @Override public void accept(final FeedRangeVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this); } @Override public void accept(GenericFeedRangeVisitor visitor, TInput input) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this, input); } @Override - public Mono acceptAsync(final FeedRangeAsyncVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - - return visitor.visitAsync(this); + public Mono accept(final FeedRangeAsyncVisitor visitor) { + checkNotNull(visitor, "Argument 'visitor' must not be null"); + return visitor.visit(this); } @Override - public Mono>> getEffectiveRangesAsync( + public Mono>> getEffectiveRanges( final IRoutingMapProvider routingMapProvider, final String containerRid, final PartitionKeyDefinition partitionKeyDefinition) { @@ -83,7 +72,7 @@ public Mono>> getEffectiveRangesAsync( } @Override - public Mono> getPartitionKeyRangesAsync( + public Mono> getPartitionKeyRanges( final IRoutingMapProvider routingMapProvider, final String containerRid, final PartitionKeyDefinition partitionKeyDefinition) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java index 0f444a714fb60..458f61f349ee6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -15,23 +15,25 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; import java.io.IOException; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; + public abstract class FeedRangeInternal extends JsonSerializable implements FeedRange { + private final static Logger LOGGER = LoggerFactory.getLogger(FeedRangeInternal.class); public abstract void accept(FeedRangeVisitor visitor); public abstract void accept(GenericFeedRangeVisitor visitor, TInput input); - public abstract Mono acceptAsync(FeedRangeAsyncVisitor visitor); + public abstract Mono accept(FeedRangeAsyncVisitor visitor); public static FeedRangeInternal convert(final FeedRange feedRange) { - if (feedRange == null) { - throw new NullPointerException("feedRange"); - } - + checkNotNull(feedRange, "Argument 'feedRange' must not be null"); if (feedRange instanceof FeedRangeInternal) { return (FeedRangeInternal)feedRange; } @@ -47,14 +49,7 @@ public static FeedRangeInternal convert(final FeedRange feedRange) { * @return A feed range */ public static FeedRangeInternal fromJsonString(String json) { - FeedRangeInternal parsedRange; - - try { - parsedRange = FeedRangeInternal.tryParse(json); - } catch (IOException e) { - throw new IllegalArgumentException( - String.format("Unable to parse JSON %s", json), e); - } + FeedRangeInternal parsedRange = FeedRangeInternal.tryParse(json); if (parsedRange == null) { throw new IllegalArgumentException( @@ -66,12 +61,12 @@ public static FeedRangeInternal fromJsonString(String json) { return parsedRange; } - public abstract Mono>> getEffectiveRangesAsync( + public abstract Mono>> getEffectiveRanges( IRoutingMapProvider routingMapProvider, String containerRid, PartitionKeyDefinition partitionKeyDefinition); - public abstract Mono> getPartitionKeyRangesAsync( + public abstract Mono> getPartitionKeyRanges( IRoutingMapProvider routingMapProvider, String containerRid, PartitionKeyDefinition partitionKeyDefinition); @@ -88,32 +83,36 @@ public String toJsonString() { return this.toJson(); } - public static FeedRangeInternal tryParse(final String jsonString) throws IOException { - if (jsonString == null) { - throw new NullPointerException("jsonString"); - } - + public static FeedRangeInternal tryParse(final String jsonString) { + checkNotNull(jsonString, "Argument 'jsonString' must not be null"); final ObjectMapper mapper = Utils.getSimpleObjectMapper(); - JsonNode rootNode = mapper.readTree(jsonString); - - JsonNode rangeNode = rootNode.get(Constants.Properties.RANGE); - if (rangeNode != null && rangeNode.isObject()) { - Range range = new Range<>((ObjectNode)rangeNode); - return new FeedRangeEpkImpl(range); - } - JsonNode pkNode = rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY); - if (pkNode != null && pkNode.isArray()) { - PartitionKeyInternal pk = mapper.convertValue(pkNode, PartitionKeyInternal.class); - return new FeedRangePartitionKeyImpl(pk); - } - - JsonNode pkRangeIdNode = - rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID); - if (pkRangeIdNode != null && pkRangeIdNode.isTextual()) { - return new FeedRangePartitionKeyRangeImpl(pkRangeIdNode.asText()); + try { + JsonNode rootNode = mapper.readTree(jsonString); + + JsonNode rangeNode = rootNode.get(Constants.Properties.RANGE); + if (rangeNode != null && rangeNode.isObject()) { + Range range = new Range<>((ObjectNode)rangeNode); + return new FeedRangeEpkImpl(range); + } + + JsonNode pkNode = rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY); + if (pkNode != null && pkNode.isArray()) { + PartitionKeyInternal pk = mapper.convertValue(pkNode, PartitionKeyInternal.class); + return new FeedRangePartitionKeyImpl(pk); + } + + JsonNode pkRangeIdNode = + rootNode.get(Constants.Properties.FEED_RANGE_PARTITION_KEY_RANGE_ID); + if (pkRangeIdNode != null && pkRangeIdNode.isTextual()) { + return new FeedRangePartitionKeyRangeImpl(pkRangeIdNode.asText()); + } + + return null; + + } catch (final IOException ioError) { + LOGGER.debug("Failed to parse feed range JSON %s", jsonString, ioError); + return null; } - - return null; } } \ No newline at end of file diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java index 64ae40b68ef01..ee8bb5d186347 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyImpl.java @@ -15,15 +15,13 @@ import java.util.Objects; import static com.azure.cosmos.BridgeInternal.setProperty; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; final class FeedRangePartitionKeyImpl extends FeedRangeInternal { private final PartitionKeyInternal partitionKey; public FeedRangePartitionKeyImpl(PartitionKeyInternal partitionKey) { - if (partitionKey == null) { - throw new NullPointerException("partitionKey"); - } - + checkNotNull(partitionKey, "Argument 'partitionKey' must not be null"); this.partitionKey = partitionKey; } @@ -33,33 +31,24 @@ public PartitionKeyInternal getPartitionKeyInternal() { @Override public void accept(FeedRangeVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this); } @Override public void accept(GenericFeedRangeVisitor visitor, TInput input) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this, input); } @Override - public Mono acceptAsync(FeedRangeAsyncVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - - return visitor.visitAsync(this); + public Mono accept(FeedRangeAsyncVisitor visitor) { + checkNotNull(visitor, "Argument 'visitor' must not be null"); + return visitor.visit(this); } @Override - public Mono>> getEffectiveRangesAsync( + public Mono>> getEffectiveRanges( IRoutingMapProvider routingMapProvider, String containerRid, PartitionKeyDefinition partitionKeyDefinition) { @@ -75,7 +64,7 @@ public Mono>> getEffectiveRangesAsync( } @Override - public Mono> getPartitionKeyRangesAsync( + public Mono> getPartitionKeyRanges( IRoutingMapProvider routingMapProvider, String containerRid, PartitionKeyDefinition partitionKeyDefinition) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java index 75ea7605c5646..21f2d03c261a7 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeExtractorImpl.java @@ -36,7 +36,7 @@ public FeedRangePartitionKeyRangeExtractorImpl( } @Override - public Mono>> visitAsync(FeedRangePartitionKeyImpl feedRange) { + public Mono>> visit(FeedRangePartitionKeyImpl feedRange) { final RxPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); final Mono> collectionResponseObservable = this.client @@ -44,14 +44,14 @@ public Mono>> visitAsync(FeedRangePartitionKeyImpl feedRange) return collectionResponseObservable.flatMap(collectionResponse -> { final DocumentCollection collection = collectionResponse.getResource(); - return feedRange.getEffectiveRangesAsync(partitionKeyRangeCache, + return feedRange.getEffectiveRanges(partitionKeyRangeCache, collection.getResourceId(), collection.getPartitionKey()); }); } @Override - public Mono>> visitAsync(FeedRangePartitionKeyRangeImpl feedRange) { + public Mono>> visit(FeedRangePartitionKeyRangeImpl feedRange) { final RxPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); final Mono> collectionResponseObservable = this.client @@ -59,13 +59,13 @@ public Mono>> visitAsync(FeedRangePartitionKeyRangeImpl feedR return collectionResponseObservable.flatMap(collectionResponse -> { final DocumentCollection collection = collectionResponse.getResource(); - return feedRange.getEffectiveRangesAsync(partitionKeyRangeCache, + return feedRange.getEffectiveRanges(partitionKeyRangeCache, collection.getResourceId(), null); }); } @Override - public Mono>> visitAsync(FeedRangeEpkImpl feedRange) { + public Mono>> visit(FeedRangeEpkImpl feedRange) { final RxPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); final Mono> collectionResponseObservable = this.client diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java index 7a1ee0f460f8e..cde3f7582e6bb 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangePartitionKeyRangeImpl.java @@ -18,16 +18,14 @@ import java.util.Objects; import static com.azure.cosmos.BridgeInternal.setProperty; +import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; public final class FeedRangePartitionKeyRangeImpl extends FeedRangeInternal { private final String partitionKeyRangeId; private final PartitionKeyRangeIdentity partitionKeyRangeIdentity; public FeedRangePartitionKeyRangeImpl(final String partitionKeyRangeId) { - if (partitionKeyRangeId == null) { - throw new NullPointerException("partitionKeyRangeId"); - } - + checkNotNull(partitionKeyRangeId, "Argument 'partitionKeyRangeId' must not be null"); this.partitionKeyRangeId = partitionKeyRangeId; this.partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(partitionKeyRangeId); } @@ -42,33 +40,24 @@ public PartitionKeyRangeIdentity getPartitionKeyRangeIdentity() { @Override public void accept(final FeedRangeVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this); } @Override public void accept(GenericFeedRangeVisitor visitor, TInput input) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - + checkNotNull(visitor, "Argument 'visitor' must not be null"); visitor.visit(this, input); } @Override - public Mono acceptAsync(final FeedRangeAsyncVisitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor"); - } - - return visitor.visitAsync(this); + public Mono accept(final FeedRangeAsyncVisitor visitor) { + checkNotNull(visitor, "Argument 'visitor' must not be null"); + return visitor.visit(this); } @Override - public Mono>> getEffectiveRangesAsync( + public Mono>> getEffectiveRanges( final IRoutingMapProvider routingMapProvider, final String containerRid, final PartitionKeyDefinition partitionKeyDefinition) { @@ -118,7 +107,7 @@ public Mono>> getEffectiveRangesAsync( } @Override - public Mono> getPartitionKeyRangesAsync( + public Mono> getPartitionKeyRanges( final IRoutingMapProvider routingMapProvider, final String containerRid, final PartitionKeyDefinition partitionKeyDefinition) { diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java index 63e34bb79d0d2..7758ab99db6d2 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/feedranges/FeedRangeTest.java @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. package com.azure.cosmos.implementation.feedranges; import com.azure.cosmos.implementation.HttpConstants; @@ -79,7 +81,7 @@ public void feedRangeEPK_getEffectiveRangesAsync() { IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); StepVerifier .create( - FeedRangeEpk.getEffectiveRangesAsync( + FeedRangeEpk.getEffectiveRanges( routingMapProviderMock, null, null)) @@ -118,7 +120,7 @@ public void feedRangeEPK_getPartitionKeyRangesAsync() { FeedRangeEpkImpl feedRangeEpk = new FeedRangeEpkImpl(range); StepVerifier .create( - feedRangeEpk.getPartitionKeyRangesAsync( + feedRangeEpk.getPartitionKeyRanges( routingMapProviderMock, null, null)) @@ -212,7 +214,7 @@ public void feedRangePKRangeId_getEffectiveRangesAsync() { StepVerifier .create( - feedRangePartitionKeyRange.getEffectiveRangesAsync( + feedRangePartitionKeyRange.getEffectiveRanges( routingMapProviderMock, null, null)) .recordWith(ArrayList::new) .expectNextCount(1) @@ -262,7 +264,7 @@ public void feedRangePKRangeId_getEffectiveRangesAsync_Null() { StepVerifier .create( - feedRangePartitionKeyRange.getEffectiveRangesAsync( + feedRangePartitionKeyRange.getEffectiveRanges( routingMapProviderMock, null, null)) .recordWith(ArrayList::new) .expectErrorSatisfies((e) -> { @@ -297,7 +299,7 @@ public void feedRangePKRangeId_getEffectiveRangesAsync_Refresh() { StepVerifier .create( - feedRangePartitionKeyRange.getEffectiveRangesAsync( + feedRangePartitionKeyRange.getEffectiveRanges( routingMapProviderMock, null, null)) .recordWith(ArrayList::new) .expectNextCount(1) @@ -339,7 +341,7 @@ public void feedRangePKRangeId_getPartitionKeyRangesAsync() { IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); StepVerifier .create( - feedRangPartitionKeyRange.getPartitionKeyRangesAsync( + feedRangPartitionKeyRange.getPartitionKeyRanges( routingMapProviderMock, null, null)) @@ -407,7 +409,7 @@ public void feedRangePK_getEffectiveRangesAsync() { IRoutingMapProvider routingMapProviderMock = Mockito.mock(IRoutingMapProvider.class); StepVerifier .create( - feedRangePartitionKey.getEffectiveRangesAsync( + feedRangePartitionKey.getEffectiveRanges( routingMapProviderMock, null, partitionKeyDefinition)) @@ -452,7 +454,7 @@ public void feedRangePK_getPartitionKeyRangesAsync() { new FeedRangePartitionKeyImpl(partitionKey); StepVerifier .create( - feedRangPartitionKey.getPartitionKeyRangesAsync( + feedRangPartitionKey.getPartitionKeyRanges( routingMapProviderMock, null, partitionKeyDefinition)) From ee60826fd826592633307c2758075d424564f406 Mon Sep 17 00:00:00 2001 From: Fabian Meiswinkel Date: Wed, 18 Nov 2020 14:06:37 +0000 Subject: [PATCH 17/17] Update sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java Co-authored-by: Mohammad Derakhshani --- .../cosmos/implementation/feedranges/FeedRangeInternal.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java index 458f61f349ee6..23824f6dafa7c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/feedranges/FeedRangeInternal.java @@ -111,8 +111,8 @@ public static FeedRangeInternal tryParse(final String jsonString) { return null; } catch (final IOException ioError) { - LOGGER.debug("Failed to parse feed range JSON %s", jsonString, ioError); + LOGGER.debug("Failed to parse feed range JSON {}", jsonString, ioError); return null; } } -} \ No newline at end of file +}